Key to VKey conversion for Nameserver (#476)

* Key to VKey conversion for Nameserver

This change illustrates the conversion of a single key in the system
(Key<HostResource> as used in the "nameservers" field of DomainBase) to a
VKey.

It currently builds, but had some curious (possibly unrelated?) test failures
that I have not fully investigated.

* Latest round of changes, all tests pass.

* Changes requested in review.

* Fix problems with null check in VKey accessors

Add maybeGet versions of getSqlKey() and getOfyKey() that return Optional
objects and make the nameserver management routines use those instead.
This commit is contained in:
Michael Muller 2020-03-26 17:13:30 -04:00 committed by GitHub
parent c0d5c941d5
commit a5ea445c90
41 changed files with 555 additions and 249 deletions

View file

@ -30,6 +30,7 @@ import google.registry.model.EppResource;
import google.registry.model.ImmutableObject; import google.registry.model.ImmutableObject;
import google.registry.model.eppcommon.Trid; import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import google.registry.util.AppEngineServiceUtils; import google.registry.util.AppEngineServiceUtils;
import google.registry.util.Retrier; import google.registry.util.Retrier;
import javax.inject.Inject; import javax.inject.Inject;
@ -148,12 +149,12 @@ public final class AsyncTaskEnqueuer {
/** Enqueues a task to asynchronously refresh DNS for a renamed host. */ /** Enqueues a task to asynchronously refresh DNS for a renamed host. */
public void enqueueAsyncDnsRefresh(HostResource host, DateTime now) { public void enqueueAsyncDnsRefresh(HostResource host, DateTime now) {
Key<HostResource> hostKey = Key.create(host); VKey<HostResource> hostKey = host.createKey();
logger.atInfo().log("Enqueuing async DNS refresh for renamed host %s.", hostKey); logger.atInfo().log("Enqueuing async DNS refresh for renamed host %s.", hostKey);
addTaskToQueueWithRetry( addTaskToQueueWithRetry(
asyncDnsRefreshPullQueue, asyncDnsRefreshPullQueue,
TaskOptions.Builder.withMethod(Method.PULL) TaskOptions.Builder.withMethod(Method.PULL)
.param(PARAM_HOST_KEY, hostKey.getString()) .param(PARAM_HOST_KEY, hostKey.getOfyKey().getString())
.param(PARAM_REQUESTED_TIME, now.toString())); .param(PARAM_REQUESTED_TIME, now.toString()));
} }

View file

@ -85,6 +85,7 @@ import google.registry.model.poll.PendingActionNotificationResponse.HostPendingA
import google.registry.model.poll.PollMessage; import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.server.Lock; import google.registry.model.server.Lock;
import google.registry.persistence.VKey;
import google.registry.request.Action; import google.registry.request.Action;
import google.registry.request.Response; import google.registry.request.Response;
import google.registry.request.auth.Auth; import google.registry.request.auth.Auth;
@ -284,7 +285,9 @@ public class DeleteContactsAndHostsAction implements Runnable {
if (resourceKey.getKind().equals(KIND_CONTACT)) { if (resourceKey.getKind().equals(KIND_CONTACT)) {
return domain.getReferencedContacts().contains(resourceKey); return domain.getReferencedContacts().contains(resourceKey);
} else if (resourceKey.getKind().equals(KIND_HOST)) { } else if (resourceKey.getKind().equals(KIND_HOST)) {
return domain.getNameservers().contains(resourceKey); return domain
.getNameservers()
.contains(VKey.createOfy(HostResource.class, (Key<HostResource>) resourceKey));
} else { } else {
throw new IllegalStateException("EPP resource key of unknown type: " + resourceKey); throw new IllegalStateException("EPP resource key of unknown type: " + resourceKey);
} }

View file

@ -52,6 +52,7 @@ import google.registry.mapreduce.inputs.NullInput;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.model.server.Lock; import google.registry.model.server.Lock;
import google.registry.persistence.VKey;
import google.registry.request.Action; import google.registry.request.Action;
import google.registry.request.Response; import google.registry.request.Response;
import google.registry.request.auth.Auth; import google.registry.request.auth.Auth;
@ -206,7 +207,9 @@ public class RefreshDnsOnHostRenameAction implements Runnable {
Key<HostResource> referencingHostKey = null; Key<HostResource> referencingHostKey = null;
for (DnsRefreshRequest request : refreshRequests) { for (DnsRefreshRequest request : refreshRequests) {
if (isActive(domain, request.lastUpdateTime()) if (isActive(domain, request.lastUpdateTime())
&& domain.getNameservers().contains(request.hostKey())) { && domain
.getNameservers()
.contains(VKey.createOfy(HostResource.class, request.hostKey()))) {
referencingHostKey = request.hostKey(); referencingHostKey = request.hostKey();
break; break;
} }

View file

@ -80,11 +80,9 @@ public final class ResourceFlowUtils {
final Function<DomainBase, ImmutableSet<?>> getPotentialReferences) throws EppException { final Function<DomainBase, ImmutableSet<?>> getPotentialReferences) throws EppException {
// Enter a transactionless context briefly. // Enter a transactionless context briefly.
EppException failfastException = EppException failfastException =
tm() tm().doTransactionless(
.doTransactionless(
() -> { () -> {
final ForeignKeyIndex<R> fki = final ForeignKeyIndex<R> fki = ForeignKeyIndex.load(resourceClass, targetId, now);
ForeignKeyIndex.load(resourceClass, targetId, now);
if (fki == null) { if (fki == null) {
return new ResourceDoesNotExistException(resourceClass, targetId); return new ResourceDoesNotExistException(resourceClass, targetId);
} }
@ -99,8 +97,7 @@ public final class ResourceFlowUtils {
.limit(FAILFAST_CHECK_COUNT) .limit(FAILFAST_CHECK_COUNT)
.keys(); .keys();
Predicate<DomainBase> predicate = Predicate<DomainBase> predicate =
domain -> domain -> getPotentialReferences.apply(domain).contains(fki.getResourceKey());
getPotentialReferences.apply(domain).contains(fki.getResourceKey());
return ofy().load().keys(keys).values().stream().anyMatch(predicate) return ofy().load().keys(keys).values().stream().anyMatch(predicate)
? new ResourceToDeleteIsReferencedException() ? new ResourceToDeleteIsReferencedException()
: null; : null;

View file

@ -14,6 +14,7 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.flows.FlowUtils.persistEntityChanges; import static google.registry.flows.FlowUtils.persistEntityChanges;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist; import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
@ -95,6 +96,7 @@ import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand; import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CreateData.DomainCreateData; import google.registry.model.eppoutput.CreateData.DomainCreateData;
import google.registry.model.eppoutput.EppResponse; import google.registry.model.eppoutput.EppResponse;
import google.registry.model.host.HostResource;
import google.registry.model.index.EppResourceIndex; import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex; import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.ObjectifyService; import google.registry.model.ofy.ObjectifyService;
@ -108,6 +110,7 @@ import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField; import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.persistence.VKey;
import google.registry.tmch.LordnTaskUtils; import google.registry.tmch.LordnTaskUtils;
import java.util.Optional; import java.util.Optional;
import javax.inject.Inject; import javax.inject.Inject;
@ -352,7 +355,11 @@ public class DomainCreateFlow implements TransactionalFlow {
.setRegistrant(command.getRegistrant()) .setRegistrant(command.getRegistrant())
.setAuthInfo(command.getAuthInfo()) .setAuthInfo(command.getAuthInfo())
.setFullyQualifiedDomainName(targetId) .setFullyQualifiedDomainName(targetId)
.setNameservers(command.getNameservers()) .setNameservers(
(ImmutableSet<VKey<HostResource>>)
command.getNameservers().stream()
.map(key -> VKey.createOfy(HostResource.class, key))
.collect(toImmutableSet()))
.setStatusValues(statuses.build()) .setStatusValues(statuses.build())
.setContacts(command.getContacts()) .setContacts(command.getContacts())
.addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, createBillingEvent)) .addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, createBillingEvent))

View file

@ -14,7 +14,6 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static com.google.common.collect.Sets.union;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyExistence; import static google.registry.flows.ResourceFlowUtils.verifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
@ -23,6 +22,7 @@ import static google.registry.flows.domain.DomainFlowUtils.handleFeeRequest;
import static google.registry.flows.domain.DomainFlowUtils.loadForeignKeyedDesignatedContacts; import static google.registry.flows.domain.DomainFlowUtils.loadForeignKeyedDesignatedContacts;
import static google.registry.model.EppResourceUtils.loadByForeignKey; import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -102,8 +102,9 @@ public final class DomainInfoFlow implements Flow {
flowCustomLogic.afterValidation( flowCustomLogic.afterValidation(
AfterValidationParameters.newBuilder().setDomain(domain).build()); AfterValidationParameters.newBuilder().setDomain(domain).build());
// Prefetch all referenced resources. Calling values() blocks until loading is done. // Prefetch all referenced resources. Calling values() blocks until loading is done.
ofy().load() // We do nameservers separately since they've been converted to VKey.
.values(union(domain.getNameservers(), domain.getReferencedContacts())).values(); tm().load(domain.getNameservers());
ofy().load().values(domain.getReferencedContacts()).values();
// Registrars can only see a few fields on unauthorized domains. // Registrars can only see a few fields on unauthorized domains.
// This is a policy decision that is left up to us by the rfcs. // This is a policy decision that is left up to us by the rfcs.
DomainInfoData.Builder infoBuilder = DomainInfoData.newBuilder() DomainInfoData.Builder infoBuilder = DomainInfoData.newBuilder()

View file

@ -15,6 +15,7 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.symmetricDifference; import static com.google.common.collect.Sets.symmetricDifference;
import static com.google.common.collect.Sets.union; import static com.google.common.collect.Sets.union;
import static google.registry.flows.FlowUtils.persistEntityChanges; import static google.registry.flows.FlowUtils.persistEntityChanges;
@ -71,9 +72,11 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppinput.EppInput; import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand; import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.EppResponse; import google.registry.model.eppoutput.EppResponse;
import google.registry.model.host.HostResource;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.persistence.VKey;
import java.util.Optional; import java.util.Optional;
import javax.inject.Inject; import javax.inject.Inject;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -243,8 +246,14 @@ public final class DomainUpdateFlow implements TransactionalFlow {
.setLastEppUpdateClientId(clientId) .setLastEppUpdateClientId(clientId)
.addStatusValues(add.getStatusValues()) .addStatusValues(add.getStatusValues())
.removeStatusValues(remove.getStatusValues()) .removeStatusValues(remove.getStatusValues())
.addNameservers(add.getNameservers()) .addNameservers(
.removeNameservers(remove.getNameservers()) add.getNameservers().stream()
.map(key -> VKey.createOfy(HostResource.class, key))
.collect(toImmutableSet()))
.removeNameservers(
remove.getNameservers().stream()
.map(key -> VKey.createOfy(HostResource.class, key))
.collect(toImmutableSet()))
.addContacts(add.getContacts()) .addContacts(add.getContacts())
.removeContacts(remove.getContacts()) .removeContacts(remove.getContacts())
.setRegistrant(firstNonNull(change.getRegistrant(), domain.getRegistrant())) .setRegistrant(firstNonNull(change.getRegistrant(), domain.getRegistrant()))

View file

@ -14,6 +14,7 @@
package google.registry.flows.host; package google.registry.flows.host;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.failfastForAsyncDelete; import static google.registry.flows.ResourceFlowUtils.failfastForAsyncDelete;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence; import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
@ -81,6 +82,17 @@ public final class HostDeleteFlow implements TransactionalFlow {
@Inject EppResponse.Builder responseBuilder; @Inject EppResponse.Builder responseBuilder;
@Inject HostDeleteFlow() {} @Inject HostDeleteFlow() {}
/**
* Hack to convert DomainBase's nameserver VKey's to Ofy Key's.
*
* <p>We currently need this because {@code failfastForAsyncDelete()} checks to see if a name is
* in the ofy keys and is used for both nameservers and contacts. When we convert contacts to
* VKey's, we can remove this and do the conversion in {@code failfastForAsyncDelete()}.
*/
private static ImmutableSet<Key<HostResource>> getNameserverOfyKeys(DomainBase domain) {
return domain.getNameservers().stream().map(key -> key.getOfyKey()).collect(toImmutableSet());
}
@Override @Override
public final EppResponse run() throws EppException { public final EppResponse run() throws EppException {
extensionManager.register(MetadataExtension.class); extensionManager.register(MetadataExtension.class);
@ -88,7 +100,7 @@ public final class HostDeleteFlow implements TransactionalFlow {
validateClientIsLoggedIn(clientId); validateClientIsLoggedIn(clientId);
DateTime now = tm().getTransactionTime(); DateTime now = tm().getTransactionTime();
validateHostName(targetId); validateHostName(targetId);
failfastForAsyncDelete(targetId, now, HostResource.class, DomainBase::getNameservers); failfastForAsyncDelete(targetId, now, HostResource.class, HostDeleteFlow::getNameserverOfyKeys);
HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now); HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now);
verifyNoDisallowedStatuses(existingHost, DISALLOWED_STATUSES); verifyNoDisallowedStatuses(existingHost, DISALLOWED_STATUSES);
if (!isSuperuser) { if (!isSuperuser) {

View file

@ -42,8 +42,10 @@ import com.google.common.collect.Ordering;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.IgnoreSave; import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Index; import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.annotation.OnLoad;
import com.googlecode.objectify.condition.IfNull; import com.googlecode.objectify.condition.IfNull;
import google.registry.flows.ResourceFlowUtils; import google.registry.flows.ResourceFlowUtils;
import google.registry.model.EppResource; import google.registry.model.EppResource;
@ -63,6 +65,7 @@ import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import google.registry.util.CollectionUtils; import google.registry.util.CollectionUtils;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
@ -130,9 +133,16 @@ public class DomainBase extends EppResource
@Index @Index
String tld; String tld;
/** References to hosts that are the nameservers for the domain. */ /**
* References to hosts that are the nameservers for the domain.
*
* <p>This is a legacy field: we have to preserve it because it is still persisted and indexed in
* the datastore, but all external references go through nsHostVKeys.
*/
@Index @ElementCollection @Transient Set<Key<HostResource>> nsHosts; @Index @ElementCollection @Transient Set<Key<HostResource>> nsHosts;
@Ignore @Transient Set<VKey<HostResource>> nsHostVKeys;
/** /**
* The union of the contacts visible via {@link #getContacts} and {@link #getRegistrant}. * The union of the contacts visible via {@link #getContacts} and {@link #getRegistrant}.
* *
@ -240,6 +250,14 @@ public class DomainBase extends EppResource
*/ */
DateTime lastTransferTime; DateTime lastTransferTime;
@OnLoad
void load() {
nsHostVKeys =
nullToEmptyImmutableCopy(nsHosts).stream()
.map(hostKey -> VKey.createOfy(HostResource.class, hostKey))
.collect(toImmutableSet());
}
public ImmutableSet<String> getSubordinateHosts() { public ImmutableSet<String> getSubordinateHosts() {
return nullToEmptyImmutableCopy(subordinateHosts); return nullToEmptyImmutableCopy(subordinateHosts);
} }
@ -299,8 +317,10 @@ public class DomainBase extends EppResource
return idnTableName; return idnTableName;
} }
public ImmutableSet<Key<HostResource>> getNameservers() { public ImmutableSet<VKey<HostResource>> getNameservers() {
return nullToEmptyImmutableCopy(nsHosts); // Since nsHostVKeys gets initialized both from setNameservers() and the OnLoad method, this
// should always be valid.
return nullToEmptyImmutableCopy(nsHostVKeys);
} }
public final String getCurrentSponsorClientId() { public final String getCurrentSponsorClientId() {
@ -482,7 +502,7 @@ public class DomainBase extends EppResource
public ImmutableSortedSet<String> loadNameserverFullyQualifiedHostNames() { public ImmutableSortedSet<String> loadNameserverFullyQualifiedHostNames() {
return ofy() return ofy()
.load() .load()
.keys(getNameservers()) .keys(getNameservers().stream().map(VKey::getOfyKey).collect(toImmutableSet()))
.values() .values()
.stream() .stream()
.map(HostResource::getFullyQualifiedHostName) .map(HostResource::getFullyQualifiedHostName)
@ -542,6 +562,14 @@ public class DomainBase extends EppResource
Builder(DomainBase instance) { Builder(DomainBase instance) {
super(instance); super(instance);
// Convert nsHosts to nsHostVKeys.
if (instance.nsHosts != null) {
instance.nsHostVKeys =
instance.nsHosts.stream()
.map(key -> VKey.createOfy(HostResource.class, key))
.collect(toImmutableSet());
}
} }
@Override @Override
@ -557,7 +585,7 @@ public class DomainBase extends EppResource
} else { // There are nameservers, so make sure INACTIVE isn't there. } else { // There are nameservers, so make sure INACTIVE isn't there.
removeStatusValue(StatusValue.INACTIVE); removeStatusValue(StatusValue.INACTIVE);
} }
checkArgumentNotNull( checkArgumentNotNull(
emptyToNull(instance.fullyQualifiedDomainName), "Missing fullyQualifiedDomainName"); emptyToNull(instance.fullyQualifiedDomainName), "Missing fullyQualifiedDomainName");
checkArgument(instance.allContacts.stream().anyMatch(IS_REGISTRANT), "Missing registrant"); checkArgument(instance.allContacts.stream().anyMatch(IS_REGISTRANT), "Missing registrant");
@ -591,30 +619,45 @@ public class DomainBase extends EppResource
return thisCastToDerived(); return thisCastToDerived();
} }
public Builder setNameservers(Key<HostResource> nameserver) { public Builder setNameservers(VKey<HostResource> nameserver) {
getInstance().nsHosts = ImmutableSet.of(nameserver); Optional<Key<HostResource>> nsKey = nameserver.maybeGetOfyKey();
if (nsKey.isPresent()) {
getInstance().nsHosts = ImmutableSet.of(nsKey.get());
} else {
getInstance().nsHosts = null;
}
getInstance().nsHostVKeys = ImmutableSet.of(nameserver);
return thisCastToDerived(); return thisCastToDerived();
} }
public Builder setNameservers(ImmutableSet<Key<HostResource>> nameservers) { public Builder setNameservers(ImmutableSet<VKey<HostResource>> nameservers) {
getInstance().nsHosts = forceEmptyToNull(nameservers); // If we have all of the ofy keys, we can set nsHosts. Otherwise, make it null.
if (nameservers != null
&& nameservers.stream().allMatch(key -> key.maybeGetOfyKey().isPresent())) {
getInstance().nsHosts =
nameservers.stream().map(key -> key.getOfyKey()).collect(toImmutableSet());
} else {
getInstance().nsHosts = null;
}
getInstance().nsHostVKeys = forceEmptyToNull(nameservers);
return thisCastToDerived(); return thisCastToDerived();
} }
public Builder addNameserver(Key<HostResource> nameserver) { public Builder addNameserver(VKey<HostResource> nameserver) {
return addNameservers(ImmutableSet.of(nameserver)); return addNameservers(ImmutableSet.of(nameserver));
} }
public Builder addNameservers(ImmutableSet<Key<HostResource>> nameservers) { public Builder addNameservers(ImmutableSet<VKey<HostResource>> nameservers) {
return setNameservers( return setNameservers(
ImmutableSet.copyOf(union(getInstance().getNameservers(), nameservers))); ImmutableSet.copyOf(union(getInstance().getNameservers(), nameservers)));
} }
public Builder removeNameserver(Key<HostResource> nameserver) { public Builder removeNameserver(VKey<HostResource> nameserver) {
return removeNameservers(ImmutableSet.of(nameserver)); return removeNameservers(ImmutableSet.of(nameserver));
} }
public Builder removeNameservers(ImmutableSet<Key<HostResource>> nameservers) { public Builder removeNameservers(ImmutableSet<VKey<HostResource>> nameservers) {
return setNameservers( return setNameservers(
ImmutableSet.copyOf(difference(getInstance().getNameservers(), nameservers))); ImmutableSet.copyOf(difference(getInstance().getNameservers(), nameservers)));
} }

View file

@ -33,6 +33,7 @@ import google.registry.model.annotations.ExternalMessagingName;
import google.registry.model.annotations.ReportedOn; import google.registry.model.annotations.ReportedOn;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.persistence.VKey;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -117,6 +118,10 @@ public class HostResource extends EppResource implements ForeignKeyedEppResource
return fullyQualifiedHostName; return fullyQualifiedHostName;
} }
public VKey<HostResource> createKey() {
return VKey.createOfy(HostResource.class, Key.create(this));
}
@Deprecated @Deprecated
@Override @Override
public HostResource cloneProjectedAtTime(DateTime now) { public HostResource cloneProjectedAtTime(DateTime now) {

View file

@ -18,10 +18,13 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.googlecode.objectify.Key;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.persistence.transaction.TransactionManager; import google.registry.persistence.transaction.TransactionManager;
import java.util.Iterator;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.StreamSupport;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/** Datastore implementation of {@link TransactionManager}. */ /** Datastore implementation of {@link TransactionManager}. */
@ -128,9 +131,22 @@ public class DatastoreTransactionManager implements TransactionManager {
throw new UnsupportedOperationException("Not available in the Datastore transaction manager"); throw new UnsupportedOperationException("Not available in the Datastore transaction manager");
} }
// TODO: add tests for these methods. They currently have some degree of test coverage because
// they are used when retrieving the nameservers which require these, as they are now loaded by
// VKey instead of by ofy Key. But ideally, there should be one set of TransactionManager
// interface tests that are applied to both the datastore and SQL implementations.
@Override @Override
public <T> Optional<T> load(VKey<T> key) { public <T> Optional<T> load(VKey<T> key) {
throw new UnsupportedOperationException("Not available in the Datastore transaction manager"); return Optional.of(getOfy().load().key(key.getOfyKey()).now());
}
@Override
public <T> ImmutableList<T> load(Iterable<VKey<T>> keys) {
Iterator<Key<T>> iter =
StreamSupport.stream(keys.spliterator(), false).map(key -> key.getOfyKey()).iterator();
// The lambda argument to keys() effectively converts Iterator -> Iterable.
return ImmutableList.copyOf(getOfy().load().keys(() -> iter).values());
} }
@Override @Override

View file

@ -36,6 +36,7 @@ import com.googlecode.objectify.impl.translate.opt.joda.MoneyStringTranslatorFac
import google.registry.config.RegistryEnvironment; import google.registry.config.RegistryEnvironment;
import google.registry.model.EntityClasses; import google.registry.model.EntityClasses;
import google.registry.model.ImmutableObject; import google.registry.model.ImmutableObject;
import google.registry.model.host.HostResource;
import google.registry.model.translators.BloomFilterOfStringTranslatorFactory; import google.registry.model.translators.BloomFilterOfStringTranslatorFactory;
import google.registry.model.translators.CidrAddressBlockTranslatorFactory; import google.registry.model.translators.CidrAddressBlockTranslatorFactory;
import google.registry.model.translators.CommitLogRevisionsTranslatorFactory; import google.registry.model.translators.CommitLogRevisionsTranslatorFactory;
@ -45,6 +46,7 @@ import google.registry.model.translators.DurationTranslatorFactory;
import google.registry.model.translators.InetAddressTranslatorFactory; import google.registry.model.translators.InetAddressTranslatorFactory;
import google.registry.model.translators.ReadableInstantUtcTranslatorFactory; import google.registry.model.translators.ReadableInstantUtcTranslatorFactory;
import google.registry.model.translators.UpdateAutoTimestampTranslatorFactory; import google.registry.model.translators.UpdateAutoTimestampTranslatorFactory;
import google.registry.model.translators.VKeyTranslatorFactory;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** /**
@ -117,17 +119,19 @@ public class ObjectifyService {
/** Register translators that allow less common types to be stored directly in Datastore. */ /** Register translators that allow less common types to be stored directly in Datastore. */
private static void registerTranslators() { private static void registerTranslators() {
for (TranslatorFactory<?> translatorFactory : ImmutableList.of( for (TranslatorFactory<?> translatorFactory :
new BloomFilterOfStringTranslatorFactory(), ImmutableList.of(
new CidrAddressBlockTranslatorFactory(), new BloomFilterOfStringTranslatorFactory(),
new CommitLogRevisionsTranslatorFactory(), new CidrAddressBlockTranslatorFactory(),
new CreateAutoTimestampTranslatorFactory(), new CommitLogRevisionsTranslatorFactory(),
new CurrencyUnitTranslatorFactory(), new CreateAutoTimestampTranslatorFactory(),
new DurationTranslatorFactory(), new CurrencyUnitTranslatorFactory(),
new InetAddressTranslatorFactory(), new DurationTranslatorFactory(),
new MoneyStringTranslatorFactory(), new InetAddressTranslatorFactory(),
new ReadableInstantUtcTranslatorFactory(), new MoneyStringTranslatorFactory(),
new UpdateAutoTimestampTranslatorFactory())) { new ReadableInstantUtcTranslatorFactory(),
new VKeyTranslatorFactory<HostResource>(HostResource.class),
new UpdateAutoTimestampTranslatorFactory())) {
factory().getTranslators().add(translatorFactory); factory().getTranslators().add(translatorFactory);
} }
} }

View file

@ -0,0 +1,84 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.model.translators;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.googlecode.objectify.Key;
import google.registry.persistence.VKey;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
* Translator factory for VKey.
*
* <p>These get translated to a string containing the URL safe encoding of the objectify key
* followed by a (url-unsafe) ampersand delimiter and the SQL key.
*/
public class VKeyTranslatorFactory<T> extends AbstractSimpleTranslatorFactory<VKey, String> {
private final Class<T> refClass;
public VKeyTranslatorFactory(Class<T> refClass) {
super(VKey.class);
this.refClass = refClass;
}
@Override
public SimpleTranslator<VKey, String> createTranslator() {
return new SimpleTranslator<VKey, String>() {
@Override
public VKey loadValue(String datastoreValue) {
int pos = datastoreValue.indexOf('&');
Key ofyKey = null;
String sqlKey = null;
if (pos > 0) {
// We have an objectify key.
ofyKey = Key.create(datastoreValue.substring(0, pos));
}
if (pos < datastoreValue.length() - 1) {
// We have an SQL key.
sqlKey = decode(datastoreValue.substring(pos + 1));
}
return VKey.create(refClass, sqlKey, ofyKey);
}
@Override
public String saveValue(VKey key) {
return ((key.getOfyKey() == null) ? "" : key.getOfyKey().getString())
+ "&"
+ ((key.getSqlKey() == null) ? "" : encode(key.getSqlKey().toString()));
}
};
}
private static String encode(String val) {
try {
return URLEncoder.encode(val, UTF_8.toString());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private static String decode(String encoded) {
try {
return URLDecoder.decode(encoded, UTF_8.toString());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -14,7 +14,10 @@
package google.registry.persistence; package google.registry.persistence;
import static com.google.common.base.Preconditions.checkState;
import google.registry.model.ImmutableObject; import google.registry.model.ImmutableObject;
import java.util.Optional;
/** /**
* VKey is an abstraction that encapsulates the key concept. * VKey is an abstraction that encapsulates the key concept.
@ -25,12 +28,12 @@ import google.registry.model.ImmutableObject;
public class VKey<T> extends ImmutableObject { public class VKey<T> extends ImmutableObject {
// The primary key for the referenced entity. // The primary key for the referenced entity.
private Object primaryKey; private final Object primaryKey;
// The objectify key for the referenced entity. // The objectify key for the referenced entity.
private com.googlecode.objectify.Key<T> ofyKey; private final com.googlecode.objectify.Key<T> ofyKey;
private Class<? extends T> kind; private final Class<? extends T> kind;
private VKey(Class<? extends T> kind, com.googlecode.objectify.Key<T> ofyKey, Object primaryKey) { private VKey(Class<? extends T> kind, com.googlecode.objectify.Key<T> ofyKey, Object primaryKey) {
this.kind = kind; this.kind = kind;
@ -52,17 +55,34 @@ public class VKey<T> extends ImmutableObject {
return new VKey(kind, ofyKey, null); return new VKey(kind, ofyKey, null);
} }
public static <T> VKey<T> create(
Class<? extends T> kind, Object primaryKey, com.googlecode.objectify.Key ofyKey) {
return new VKey(kind, ofyKey, primaryKey);
}
public Class<? extends T> getKind() { public Class<? extends T> getKind() {
return this.kind; return this.kind;
} }
/** Returns the SQL primary key. */ /** Returns the SQL primary key. */
public Object getSqlKey() { public Object getSqlKey() {
checkState(primaryKey != null, "Attempting obtain a null SQL key.");
return this.primaryKey; return this.primaryKey;
} }
/** Returns the SQL primary key if it exists. */
public Optional<Object> maybeGetSqlKey() {
return Optional.of(this.primaryKey);
}
/** Returns the objectify key. */ /** Returns the objectify key. */
public com.googlecode.objectify.Key<T> getOfyKey() { public com.googlecode.objectify.Key<T> getOfyKey() {
checkState(ofyKey != null, "Attempting obtain a null Objectify key.");
return this.ofyKey; return this.ofyKey;
} }
/** Returns the objectify key if it exists. */
public Optional<com.googlecode.objectify.Key<T>> maybeGetOfyKey() {
return Optional.of(this.ofyKey);
}
} }

View file

@ -15,6 +15,7 @@
package google.registry.persistence.transaction; package google.registry.persistence.transaction;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
@ -26,8 +27,10 @@ import com.google.common.flogger.FluentLogger;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import google.registry.util.Clock; import google.registry.util.Clock;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.NoSuchElementException;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.StreamSupport;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction; import javax.persistence.EntityTransaction;
@ -235,6 +238,23 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
return Optional.ofNullable(getEntityManager().find(key.getKind(), key.getSqlKey())); return Optional.ofNullable(getEntityManager().find(key.getKind(), key.getSqlKey()));
} }
@Override
public <T> ImmutableList<T> load(Iterable<VKey<T>> keys) {
checkArgumentNotNull(keys, "keys must be specified");
assertInTransaction();
return StreamSupport.stream(keys.spliterator(), false)
.map(
key -> {
T entity = getEntityManager().find(key.getKind(), key.getSqlKey());
if (entity == null) {
throw new NoSuchElementException(
key.getKind().getName() + " with key " + key.getSqlKey() + " not found.");
}
return entity;
})
.collect(toImmutableList());
}
@Override @Override
public <T> ImmutableList<T> loadAll(Class<T> clazz) { public <T> ImmutableList<T> loadAll(Class<T> clazz) {
checkArgumentNotNull(clazz, "clazz must be specified"); checkArgumentNotNull(clazz, "clazz must be specified");

View file

@ -110,6 +110,13 @@ public interface TransactionManager {
/** Loads the entity by its id, returns empty if the entity doesn't exist. */ /** Loads the entity by its id, returns empty if the entity doesn't exist. */
<T> Optional<T> load(VKey<T> key); <T> Optional<T> load(VKey<T> key);
/**
* Leads the set of entities by their key id.
*
* @throws NoSuchElementException if any of the keys are not found.
*/
<T> ImmutableList<T> load(Iterable<VKey<T>> keys);
/** Loads all entities of the given type, returns empty if there is no such entity. */ /** Loads all entities of the given type, returns empty if there is no such entity. */
<T> ImmutableList<T> loadAll(Class<T> clazz); <T> ImmutableList<T> loadAll(Class<T> clazz);

View file

@ -21,6 +21,7 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap; import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
import static google.registry.model.EppResourceUtils.isLinked; import static google.registry.model.EppResourceUtils.isLinked;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.rdap.RdapIcannStandardInformation.CONTACT_REDACTED_VALUE; import static google.registry.rdap.RdapIcannStandardInformation.CONTACT_REDACTED_VALUE;
import static google.registry.util.CollectionUtils.union; import static google.registry.util.CollectionUtils.union;
@ -341,8 +342,8 @@ public class RdapJsonFormatter {
// Kick off the database loads of the nameservers that we will need, so it can load // Kick off the database loads of the nameservers that we will need, so it can load
// asynchronously while we load and process the contacts. // asynchronously while we load and process the contacts.
Map<Key<HostResource>, HostResource> loadedHosts = ImmutableSet<HostResource> loadedHosts =
ofy().load().keys(domainBase.getNameservers()); ImmutableSet.copyOf(tm().load(domainBase.getNameservers()));
// Load the registrant and other contacts and add them to the data. // Load the registrant and other contacts and add them to the data.
Map<Key<ContactResource>, ContactResource> loadedContacts = Map<Key<ContactResource>, ContactResource> loadedContacts =
ofy().load().keys(domainBase.getReferencedContacts()); ofy().load().keys(domainBase.getReferencedContacts());
@ -378,8 +379,7 @@ public class RdapJsonFormatter {
} }
// Add the nameservers to the data; the load was kicked off above for efficiency. // Add the nameservers to the data; the load was kicked off above for efficiency.
// RDAP Response Profile 2.9: we MUST have the nameservers // RDAP Response Profile 2.9: we MUST have the nameservers
for (HostResource hostResource : for (HostResource hostResource : HOST_RESOURCE_ORDERING.immutableSortedCopy(loadedHosts)) {
HOST_RESOURCE_ORDERING.immutableSortedCopy(loadedHosts.values())) {
builder.nameserversBuilder().add(createRdapNameserver(hostResource, OutputDataType.INTERNAL)); builder.nameserversBuilder().add(createRdapNameserver(hostResource, OutputDataType.INTERNAL));
} }

View file

@ -19,7 +19,7 @@ import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.collect.Sets.difference; import static com.google.common.collect.Sets.difference;
import static google.registry.model.EppResourceUtils.checkResourcesExist; import static google.registry.model.EppResourceUtils.checkResourcesExist;
import static google.registry.model.EppResourceUtils.loadByForeignKey; import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.PreconditionsUtils.checkArgumentPresent; import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
import static org.joda.time.DateTimeZone.UTC; import static org.joda.time.DateTimeZone.UTC;
@ -149,7 +149,7 @@ final class UniformRapidSuspensionCommand extends MutatingEppToolCommand {
private ImmutableSortedSet<String> getExistingNameservers(DomainBase domain) { private ImmutableSortedSet<String> getExistingNameservers(DomainBase domain) {
ImmutableSortedSet.Builder<String> nameservers = ImmutableSortedSet.naturalOrder(); ImmutableSortedSet.Builder<String> nameservers = ImmutableSortedSet.naturalOrder();
for (HostResource host : ofy().load().keys(domain.getNameservers()).values()) { for (HostResource host : tm().load(domain.getNameservers())) {
nameservers.add(host.getForeignKey()); nameservers.add(host.getForeignKey());
} }
return nameservers.build(); return nameservers.build();

View file

@ -20,7 +20,7 @@ import static com.google.common.collect.Iterators.filter;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static google.registry.mapreduce.inputs.EppResourceInputs.createEntityInput; import static google.registry.mapreduce.inputs.EppResourceInputs.createEntityInput;
import static google.registry.model.EppResourceUtils.loadAtPointInTime; import static google.registry.model.EppResourceUtils.loadAtPointInTime;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST; import static google.registry.request.Action.Method.POST;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static org.joda.time.DateTimeZone.UTC; import static org.joda.time.DateTimeZone.UTC;
@ -214,7 +214,7 @@ public class GenerateZoneFilesAction implements Runnable, JsonActionRunner.JsonA
private void emitForSubordinateHosts(DomainBase domain) { private void emitForSubordinateHosts(DomainBase domain) {
ImmutableSet<String> subordinateHosts = domain.getSubordinateHosts(); ImmutableSet<String> subordinateHosts = domain.getSubordinateHosts();
if (!subordinateHosts.isEmpty()) { if (!subordinateHosts.isEmpty()) {
for (HostResource unprojectedHost : ofy().load().keys(domain.getNameservers()).values()) { for (HostResource unprojectedHost : tm().load(domain.getNameservers())) {
HostResource host = loadAtPointInTime(unprojectedHost, exportTime).now(); HostResource host = loadAtPointInTime(unprojectedHost, exportTime).now();
// A null means the host was deleted (or not created) at this time. // A null means the host was deleted (or not created) at this time.
if ((host != null) && subordinateHosts.contains(host.getFullyQualifiedHostName())) { if ((host != null) && subordinateHosts.contains(host.getFullyQualifiedHostName())) {
@ -283,7 +283,7 @@ public class GenerateZoneFilesAction implements Runnable, JsonActionRunner.JsonA
Duration dnsDefaultDsTtl) { Duration dnsDefaultDsTtl) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
String domainLabel = stripTld(domain.getFullyQualifiedDomainName(), domain.getTld()); String domainLabel = stripTld(domain.getFullyQualifiedDomainName(), domain.getTld());
for (HostResource nameserver : ofy().load().keys(domain.getNameservers()).values()) { for (HostResource nameserver : tm().load(domain.getNameservers())) {
result.append(String.format( result.append(String.format(
NS_FORMAT, NS_FORMAT,
domainLabel, domainLabel,

View file

@ -614,7 +614,7 @@ public class DeleteContactsAndHostsActionTest
.hasDeletionTime(END_OF_TIME); .hasDeletionTime(END_OF_TIME);
DomainBase domain = DomainBase domain =
loadByForeignKey(DomainBase.class, "example.tld", clock.nowUtc()).get(); loadByForeignKey(DomainBase.class, "example.tld", clock.nowUtc()).get();
assertThat(domain.getNameservers()).contains(Key.create(hostAfter)); assertThat(domain.getNameservers()).contains(hostAfter.createKey());
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(hostAfter, HOST_DELETE_FAILURE); HistoryEntry historyEntry = getOnlyHistoryEntryOfType(hostAfter, HOST_DELETE_FAILURE);
assertPollMessageFor( assertPollMessageFor(
historyEntry, historyEntry,
@ -684,7 +684,7 @@ public class DeleteContactsAndHostsActionTest
persistResource( persistResource(
newDomainBase("example.tld") newDomainBase("example.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(host.createKey()))
.setDeletionTime(clock.nowUtc().minusDays(5)) .setDeletionTime(clock.nowUtc().minusDays(5))
.build()); .build());
enqueuer.enqueueAsyncDelete( enqueuer.enqueueAsyncDelete(
@ -943,7 +943,7 @@ public class DeleteContactsAndHostsActionTest
return persistResource( return persistResource(
newDomainBase(domainName, contact) newDomainBase(domainName, contact)
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(host.createKey()))
.build()); .build());
} }

View file

@ -38,12 +38,12 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import com.google.common.util.concurrent.RateLimiter; import com.google.common.util.concurrent.RateLimiter;
import com.googlecode.objectify.Key;
import google.registry.dns.writer.clouddns.CloudDnsWriter.ZoneStateException; import google.registry.dns.writer.clouddns.CloudDnsWriter.ZoneStateException;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.secdns.DelegationSignerData; import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import google.registry.testing.AppEngineRule; import google.registry.testing.AppEngineRule;
import google.registry.util.Retrier; import google.registry.util.Retrier;
import google.registry.util.SystemClock; import google.registry.util.SystemClock;
@ -292,9 +292,9 @@ public class CloudDnsWriterTest {
dsDataBuilder.add(DelegationSignerData.create(i, 3, 1, base16().decode("1234567890ABCDEF"))); dsDataBuilder.add(DelegationSignerData.create(i, 3, 1, base16().decode("1234567890ABCDEF")));
} }
ImmutableSet.Builder<Key<HostResource>> hostResourceRefBuilder = new ImmutableSet.Builder<>(); ImmutableSet.Builder<VKey<HostResource>> hostResourceRefBuilder = new ImmutableSet.Builder<>();
for (HostResource nameserver : nameservers) { for (HostResource nameserver : nameservers) {
hostResourceRefBuilder.add(Key.create(nameserver)); hostResourceRefBuilder.add(nameserver.createKey());
} }
return newDomainBase(domainName) return newDomainBase(domainName)

View file

@ -36,7 +36,6 @@ import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import com.googlecode.objectify.Key;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.secdns.DelegationSignerData; import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
@ -106,7 +105,7 @@ public class DnsUpdateWriterTest {
DomainBase domain = DomainBase domain =
persistActiveDomain("example.tld") persistActiveDomain("example.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host1), Key.create(host2))) .setNameservers(ImmutableSet.of(host1.createKey(), host2.createKey()))
.build(); .build();
persistResource(domain); persistResource(domain);
@ -127,7 +126,7 @@ public class DnsUpdateWriterTest {
DomainBase domain1 = DomainBase domain1 =
persistActiveDomain("example1.tld") persistActiveDomain("example1.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host1))) .setNameservers(ImmutableSet.of(host1.createKey()))
.build(); .build();
persistResource(domain1); persistResource(domain1);
@ -135,7 +134,7 @@ public class DnsUpdateWriterTest {
DomainBase domain2 = DomainBase domain2 =
persistActiveDomain("example2.tld") persistActiveDomain("example2.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host2))) .setNameservers(ImmutableSet.of(host2.createKey()))
.build(); .build();
persistResource(domain2); persistResource(domain2);
@ -151,7 +150,7 @@ public class DnsUpdateWriterTest {
DomainBase domain1 = DomainBase domain1 =
persistActiveDomain("example1.tld") persistActiveDomain("example1.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host1))) .setNameservers(ImmutableSet.of(host1.createKey()))
.build(); .build();
persistResource(domain1); persistResource(domain1);
@ -159,7 +158,7 @@ public class DnsUpdateWriterTest {
DomainBase domain2 = DomainBase domain2 =
persistActiveDomain("example2.tld") persistActiveDomain("example2.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host2))) .setNameservers(ImmutableSet.of(host2.createKey()))
.build(); .build();
persistResource(domain2); persistResource(domain2);
@ -182,7 +181,7 @@ public class DnsUpdateWriterTest {
DomainBase domain = DomainBase domain =
persistActiveDomain("example.tld") persistActiveDomain("example.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(persistActiveHost("ns1.example.tld")))) .setNameservers(ImmutableSet.of(persistActiveHost("ns1.example.tld").createKey()))
.setDsData( .setDsData(
ImmutableSet.of( ImmutableSet.of(
DelegationSignerData.create(1, 3, 1, base16().decode("0123456789ABCDEF")))) DelegationSignerData.create(1, 3, 1, base16().decode("0123456789ABCDEF"))))
@ -207,7 +206,7 @@ public class DnsUpdateWriterTest {
persistActiveDomain("example.tld") persistActiveDomain("example.tld")
.asBuilder() .asBuilder()
.addStatusValue(StatusValue.SERVER_HOLD) .addStatusValue(StatusValue.SERVER_HOLD)
.setNameservers(ImmutableSet.of(Key.create(persistActiveHost("ns1.example.tld")))) .setNameservers(ImmutableSet.of(persistActiveHost("ns1.example.tld").createKey()))
.build(); .build();
persistResource(domain); persistResource(domain);
@ -251,7 +250,7 @@ public class DnsUpdateWriterTest {
newDomainBase("example.tld") newDomainBase("example.tld")
.asBuilder() .asBuilder()
.addSubordinateHost("ns1.example.tld") .addSubordinateHost("ns1.example.tld")
.addNameserver(Key.create(host)) .addNameserver(host.createKey())
.build()); .build());
writer.publishHost("ns1.example.tld"); writer.publishHost("ns1.example.tld");
@ -290,7 +289,7 @@ public class DnsUpdateWriterTest {
persistResource( persistResource(
persistActiveDomain("example.tld") persistActiveDomain("example.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(persistActiveHost("ns1.example.com")))) .setNameservers(ImmutableSet.of(persistActiveHost("ns1.example.com").createKey()))
.build()); .build());
writer.publishHost("ns1.example.tld"); writer.publishHost("ns1.example.tld");
@ -324,7 +323,7 @@ public class DnsUpdateWriterTest {
.asBuilder() .asBuilder()
.addSubordinateHost("ns1.example.tld") .addSubordinateHost("ns1.example.tld")
.addNameservers( .addNameservers(
ImmutableSet.of(Key.create(externalNameserver), Key.create(inBailiwickNameserver))) ImmutableSet.of(externalNameserver.createKey(), inBailiwickNameserver.createKey()))
.build()); .build());
writer.publishDomain("example.tld"); writer.publishDomain("example.tld");
@ -359,7 +358,7 @@ public class DnsUpdateWriterTest {
.asBuilder() .asBuilder()
.addSubordinateHost("ns1.example.tld") .addSubordinateHost("ns1.example.tld")
.addSubordinateHost("foo.example.tld") .addSubordinateHost("foo.example.tld")
.addNameserver(Key.create(inBailiwickNameserver)) .addNameserver(inBailiwickNameserver.createKey())
.build()); .build());
writer.publishDomain("example.tld"); writer.publishDomain("example.tld");
@ -383,7 +382,7 @@ public class DnsUpdateWriterTest {
DomainBase domain = DomainBase domain =
persistActiveDomain("example.tld") persistActiveDomain("example.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(persistActiveHost("ns1.example.tld")))) .setNameservers(ImmutableSet.of(persistActiveHost("ns1.example.tld").createKey()))
.build(); .build();
persistResource(domain); persistResource(domain);
when(mockResolver.send(any(Message.class))).thenReturn(messageWithResponseCode(Rcode.SERVFAIL)); when(mockResolver.send(any(Message.class))).thenReturn(messageWithResponseCode(Rcode.SERVFAIL));

View file

@ -693,7 +693,7 @@ public class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow,
loadByForeignKey(DomainBase.class, getUniqueIdFromCommand(), clock.nowUtc()) loadByForeignKey(DomainBase.class, getUniqueIdFromCommand(), clock.nowUtc())
.get() .get()
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(host.createKey()))
.build()); .build());
// Persist another domain that's already been deleted and references this contact and host. // Persist another domain that's already been deleted and references this contact and host.
persistResource( persistResource(
@ -701,7 +701,7 @@ public class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow,
.asBuilder() .asBuilder()
.setRegistrant( .setRegistrant(
Key.create(loadByForeignKey(ContactResource.class, "sh8013", clock.nowUtc()).get())) Key.create(loadByForeignKey(ContactResource.class, "sh8013", clock.nowUtc()).get()))
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(host.createKey()))
.setDeletionTime(START_OF_TIME) .setDeletionTime(START_OF_TIME)
.build()); .build());
clock.advanceOneMilli(); clock.advanceOneMilli();

View file

@ -118,7 +118,7 @@ public class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Dom
DesignatedContact.create(Type.ADMIN, Key.create(contact)), DesignatedContact.create(Type.ADMIN, Key.create(contact)),
DesignatedContact.create(Type.TECH, Key.create(contact)))) DesignatedContact.create(Type.TECH, Key.create(contact))))
.setNameservers( .setNameservers(
inactive ? null : ImmutableSet.of(Key.create(host1), Key.create(host2))) inactive ? null : ImmutableSet.of(host1.createKey(), host2.createKey()))
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("2fooBAR"))) .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("2fooBAR")))
.build()); .build());
// Set the superordinate domain of ns1.example.com to example.com. In reality, this would have // Set the superordinate domain of ns1.example.com to example.com. In reality, this would have
@ -294,7 +294,7 @@ public class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Dom
ImmutableSet.of( ImmutableSet.of(
DelegationSignerData.create( DelegationSignerData.create(
12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC")))) 12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC"))))
.setNameservers(ImmutableSet.of(Key.create(host1), Key.create(host3))) .setNameservers(ImmutableSet.of(host1.createKey(), host3.createKey()))
.build()); .build());
doSuccessfulTest("domain_info_response_dsdata.xml", false); doSuccessfulTest("domain_info_response_dsdata.xml", false);
} }
@ -843,7 +843,9 @@ public class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Dom
Key.getKind(ContactResource.class), Key.getKind(ContactResource.class),
Key.getKind(HostResource.class))))) Key.getKind(HostResource.class)))))
.count(); .count();
assertThat(numReadsWithContactsOrHosts).isEqualTo(1); // Nameserver keys now get persisted twice (because they are stored in nsHostsVKeys), so we
// check for two loads instead of 1.
assertThat(numReadsWithContactsOrHosts).isEqualTo(2);
} }
@Test @Test

View file

@ -88,6 +88,7 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import org.joda.money.Money; import org.joda.money.Money;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -138,7 +139,7 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
DesignatedContact.create(Type.ADMIN, Key.create(mak21Contact)), DesignatedContact.create(Type.ADMIN, Key.create(mak21Contact)),
DesignatedContact.create(Type.BILLING, Key.create(mak21Contact)))) DesignatedContact.create(Type.BILLING, Key.create(mak21Contact))))
.setRegistrant(Key.create(mak21Contact)) .setRegistrant(Key.create(mak21Contact))
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(host.createKey()))
.build()); .build());
historyEntryDomainCreate = historyEntryDomainCreate =
persistResource( persistResource(
@ -161,7 +162,7 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
ImmutableSet.of( ImmutableSet.of(
DesignatedContact.create(Type.TECH, Key.create(sh8013Contact)), DesignatedContact.create(Type.TECH, Key.create(sh8013Contact)),
DesignatedContact.create(Type.ADMIN, Key.create(unusedContact)))) DesignatedContact.create(Type.ADMIN, Key.create(unusedContact))))
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(host.createKey()))
.build()); .build());
historyEntryDomainCreate = historyEntryDomainCreate =
persistResource( persistResource(
@ -255,14 +256,14 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
} }
private void modifyDomainToHave13Nameservers() throws Exception { private void modifyDomainToHave13Nameservers() throws Exception {
ImmutableSet.Builder<Key<HostResource>> nameservers = new ImmutableSet.Builder<>(); ImmutableSet.Builder<VKey<HostResource>> nameservers = new ImmutableSet.Builder<>();
for (int i = 1; i < 15; i++) { for (int i = 1; i < 15; i++) {
if (i != 2) { // Skip 2 since that's the one that the tests will add. if (i != 2) { // Skip 2 since that's the one that the tests will add.
nameservers.add( nameservers.add(
Key.create( loadByForeignKey(
loadByForeignKey( HostResource.class, String.format("ns%d.example.foo", i), clock.nowUtc())
HostResource.class, String.format("ns%d.example.foo", i), clock.nowUtc()) .get()
.get())); .createKey());
} }
} }
persistResource( persistResource(
@ -285,11 +286,11 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
persistDomain(); persistDomain();
setEppInput("domain_update_max_everything.xml"); setEppInput("domain_update_max_everything.xml");
// Create 26 hosts and 8 contacts. Start the domain with half of them. // Create 26 hosts and 8 contacts. Start the domain with half of them.
ImmutableSet.Builder<Key<HostResource>> nameservers = new ImmutableSet.Builder<>(); ImmutableSet.Builder<VKey<HostResource>> nameservers = new ImmutableSet.Builder<>();
for (int i = 0; i < 26; i++) { for (int i = 0; i < 26; i++) {
HostResource host = persistActiveHost(String.format("max_test_%d.example.tld", i)); HostResource host = persistActiveHost(String.format("max_test_%d.example.tld", i));
if (i < 13) { if (i < 13) {
nameservers.add(Key.create(host)); nameservers.add(host.createKey());
} }
} }
ImmutableList.Builder<DesignatedContact> contactsBuilder = new ImmutableList.Builder<>(); ImmutableList.Builder<DesignatedContact> contactsBuilder = new ImmutableList.Builder<>();
@ -376,15 +377,15 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
.addSubordinateHost("ns2.example.tld") .addSubordinateHost("ns2.example.tld")
.setNameservers( .setNameservers(
ImmutableSet.of( ImmutableSet.of(
Key.create( loadByForeignKey(HostResource.class, "ns1.example.tld", clock.nowUtc())
loadByForeignKey(HostResource.class, "ns1.example.tld", clock.nowUtc()) .get()
.get()))) .createKey()))
.build()); .build());
clock.advanceOneMilli(); clock.advanceOneMilli();
assertTransactionalFlow(true); assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("generic_success_response.xml")); runFlowAssertResponse(loadFile("generic_success_response.xml"));
domain = reloadResourceByForeignKey(); domain = reloadResourceByForeignKey();
assertThat(domain.getNameservers()).containsExactly(Key.create(addedHost)); assertThat(domain.getNameservers()).containsExactly(addedHost.createKey());
assertThat(domain.getSubordinateHosts()).containsExactly("ns1.example.tld", "ns2.example.tld"); assertThat(domain.getSubordinateHosts()).containsExactly("ns1.example.tld", "ns2.example.tld");
HostResource existingHost = HostResource existingHost =
loadByForeignKey(HostResource.class, "ns1.example.tld", clock.nowUtc()).get(); loadByForeignKey(HostResource.class, "ns1.example.tld", clock.nowUtc()).get();
@ -1058,9 +1059,9 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
.asBuilder() .asBuilder()
.setNameservers( .setNameservers(
ImmutableSet.of( ImmutableSet.of(
Key.create( loadByForeignKey(HostResource.class, "ns1.example.foo", clock.nowUtc())
loadByForeignKey(HostResource.class, "ns1.example.foo", clock.nowUtc()) .get()
.get()))) .createKey()))
.build()); .build());
EppException thrown = assertThrows(AddRemoveSameValueException.class, this::runFlow); EppException thrown = assertThrows(AddRemoveSameValueException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
@ -1198,13 +1199,15 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
.build()); .build());
assertThat(reloadResourceByForeignKey().getNameservers()) assertThat(reloadResourceByForeignKey().getNameservers())
.doesNotContain( .doesNotContain(
Key.create( loadByForeignKey(HostResource.class, "ns2.example.foo", clock.nowUtc())
loadByForeignKey(HostResource.class, "ns2.example.foo", clock.nowUtc()).get())); .get()
.createKey());
runFlow(); runFlow();
assertThat(reloadResourceByForeignKey().getNameservers()) assertThat(reloadResourceByForeignKey().getNameservers())
.contains( .contains(
Key.create( loadByForeignKey(HostResource.class, "ns2.example.foo", clock.nowUtc())
loadByForeignKey(HostResource.class, "ns2.example.foo", clock.nowUtc()).get())); .get()
.createKey());
} }
@Test @Test
@ -1275,8 +1278,9 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
reloadResourceByForeignKey() reloadResourceByForeignKey()
.asBuilder() .asBuilder()
.addNameserver( .addNameserver(
Key.create( loadByForeignKey(HostResource.class, "ns2.example.foo", clock.nowUtc())
loadByForeignKey(HostResource.class, "ns2.example.foo", clock.nowUtc()).get())) .get()
.createKey())
.build()); .build());
persistResource( persistResource(
Registry.get("tld") Registry.get("tld")
@ -1286,8 +1290,9 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
.build()); .build());
assertThat(reloadResourceByForeignKey().getNameservers()) assertThat(reloadResourceByForeignKey().getNameservers())
.contains( .contains(
Key.create( loadByForeignKey(HostResource.class, "ns1.example.foo", clock.nowUtc())
loadByForeignKey(HostResource.class, "ns1.example.foo", clock.nowUtc()).get())); .get()
.createKey());
clock.advanceOneMilli(); clock.advanceOneMilli();
runFlow(); runFlow();
assertThat(reloadResourceByForeignKey().getNameservers()) assertThat(reloadResourceByForeignKey().getNameservers())

View file

@ -284,7 +284,7 @@ public class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Hos
persistResource( persistResource(
newDomainBase("example.tld") newDomainBase("example.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(persistActiveHost("ns1.example.tld")))) .setNameservers(ImmutableSet.of(persistActiveHost("ns1.example.tld").createKey()))
.build()); .build());
EppException thrown = assertThrows(ResourceToDeleteIsReferencedException.class, this::runFlow); EppException thrown = assertThrows(ResourceToDeleteIsReferencedException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();

View file

@ -92,7 +92,7 @@ public class HostInfoFlowTest extends ResourceFlowTestCase<HostInfoFlow, HostRes
persistResource( persistResource(
newDomainBase("example.foobar") newDomainBase("example.foobar")
.asBuilder() .asBuilder()
.addNameserver(Key.create(persistHostResource())) .addNameserver(persistHostResource().createKey())
.build()); .build());
assertTransactionalFlow(false); assertTransactionalFlow(false);
// Check that the persisted host info was returned. // Check that the persisted host info was returned.

View file

@ -195,7 +195,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
newDomainBase("test.xn--q9jyb4c") newDomainBase("test.xn--q9jyb4c")
.asBuilder() .asBuilder()
.setDeletionTime(END_OF_TIME) .setDeletionTime(END_OF_TIME)
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(host.createKey()))
.build()); .build());
HostResource renamedHost = doSuccessfulTest(); HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.isSubordinate()).isTrue(); assertThat(renamedHost.isSubordinate()).isTrue();

View file

@ -54,6 +54,7 @@ import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import org.joda.money.Money; import org.joda.money.Money;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.Before; import org.junit.Before;
@ -65,19 +66,20 @@ public class DomainBaseTest extends EntityTestCase {
private DomainBase domain; private DomainBase domain;
private Key<BillingEvent.OneTime> oneTimeBillKey; private Key<BillingEvent.OneTime> oneTimeBillKey;
private Key<BillingEvent.Recurring> recurringBillKey; private Key<BillingEvent.Recurring> recurringBillKey;
private Key<DomainBase> domainKey;
@Before @Before
public void setUp() { public void setUp() {
createTld("com"); createTld("com");
Key<DomainBase> domainKey = Key.create(null, DomainBase.class, "4-COM"); domainKey = Key.create(null, DomainBase.class, "4-COM");
Key<HostResource> hostKey = VKey<HostResource> hostKey =
Key.create( persistResource(
persistResource(
new HostResource.Builder() new HostResource.Builder()
.setFullyQualifiedHostName("ns1.example.com") .setFullyQualifiedHostName("ns1.example.com")
.setSuperordinateDomain(domainKey) .setSuperordinateDomain(domainKey)
.setRepoId("1-COM") .setRepoId("1-COM")
.build())); .build())
.createKey();
Key<ContactResource> contact1Key = Key<ContactResource> contact1Key =
Key.create( Key.create(
persistResource( persistResource(
@ -219,7 +221,7 @@ public class DomainBaseTest extends EntityTestCase {
assertThat( assertThat(
newDomainBase("example.com") newDomainBase("example.com")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(newHostResource("foo.example.tld")))) .setNameservers(ImmutableSet.of(newHostResource("foo.example.tld").createKey()))
.build() .build()
.nsHosts) .nsHosts)
.isNotNull(); .isNotNull();
@ -266,8 +268,8 @@ public class DomainBaseTest extends EntityTestCase {
@Test @Test
public void testImplicitStatusValues() { public void testImplicitStatusValues() {
ImmutableSet<Key<HostResource>> nameservers = ImmutableSet<VKey<HostResource>> nameservers =
ImmutableSet.of(Key.create(newHostResource("foo.example.tld"))); ImmutableSet.of(newHostResource("foo.example.tld").createKey());
StatusValue[] statuses = {StatusValue.OK}; StatusValue[] statuses = {StatusValue.OK};
// OK is implicit if there's no other statuses but there are nameservers. // OK is implicit if there's no other statuses but there are nameservers.
assertAboutDomains() assertAboutDomains()
@ -769,4 +771,60 @@ public class DomainBaseTest extends EntityTestCase {
assertThat(getOnlyElement(clone.getGracePeriods()).getType()) assertThat(getOnlyElement(clone.getGracePeriods()).getType())
.isEqualTo(GracePeriodStatus.TRANSFER); .isEqualTo(GracePeriodStatus.TRANSFER);
} }
private static ImmutableSet<Key<HostResource>> getOfyNameservers(DomainBase domain) {
return domain.getNameservers().stream().map(key -> key.getOfyKey()).collect(toImmutableSet());
}
@Test
public void testNameservers_nsHostsOfyKeys() {
assertThat(domain.nsHosts).isEqualTo(getOfyNameservers(domain));
// Test the setNameserver that functions on a function.
VKey<HostResource> host1Key =
persistResource(
new HostResource.Builder()
.setFullyQualifiedHostName("ns2.example.com")
.setSuperordinateDomain(domainKey)
.setRepoId("2-COM")
.build())
.createKey();
DomainBase dom = new DomainBase.Builder(domain).setNameservers(host1Key).build();
assertThat(dom.getNameservers()).isEqualTo(ImmutableSet.of(host1Key));
assertThat(getOfyNameservers(dom)).isEqualTo(ImmutableSet.of(host1Key.getOfyKey()));
// Test that setting to a single host of null throws an NPE.
assertThrows(
NullPointerException.class,
() -> new DomainBase.Builder(domain).setNameservers((VKey<HostResource>) null));
// Test that setting to a set of values works.
VKey<HostResource> host2Key =
persistResource(
new HostResource.Builder()
.setFullyQualifiedHostName("ns3.example.com")
.setSuperordinateDomain(domainKey)
.setRepoId("3-COM")
.build())
.createKey();
dom =
new DomainBase.Builder(domain).setNameservers(ImmutableSet.of(host1Key, host2Key)).build();
assertThat(dom.getNameservers()).isEqualTo(ImmutableSet.of(host1Key, host2Key));
assertThat(getOfyNameservers(dom))
.isEqualTo(ImmutableSet.of(host1Key.getOfyKey(), host2Key.getOfyKey()));
// Set of values, passing null.
dom =
new DomainBase.Builder(domain)
.setNameservers((ImmutableSet<VKey<HostResource>>) null)
.build();
assertThat(dom.nsHostVKeys).isNull();
assertThat(dom.nsHosts).isNull();
// Empty set of values gets translated to null.
dom = new DomainBase.Builder(domain).setNameservers(ImmutableSet.of()).build();
assertThat(dom.nsHostVKeys).isNull();
assertThat(dom.nsHosts).isNull();
}
} }

View file

@ -45,6 +45,7 @@ import google.registry.model.host.HostResource;
import google.registry.model.registrar.Registrar; import google.registry.model.registrar.Registrar;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.rdap.RdapMetrics.EndpointType; import google.registry.rdap.RdapMetrics.EndpointType;
import google.registry.rdap.RdapMetrics.SearchType; import google.registry.rdap.RdapMetrics.SearchType;
import google.registry.rdap.RdapMetrics.WildcardType; import google.registry.rdap.RdapMetrics.WildcardType;
@ -409,7 +410,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
private void createManyDomainsAndHosts( private void createManyDomainsAndHosts(
int numActiveDomains, int numTotalDomainsPerActiveDomain, int numHosts) { int numActiveDomains, int numTotalDomainsPerActiveDomain, int numHosts) {
ImmutableSet.Builder<Key<HostResource>> hostKeysBuilder = new ImmutableSet.Builder<>(); ImmutableSet.Builder<VKey<HostResource>> hostKeysBuilder = new ImmutableSet.Builder<>();
ImmutableSet.Builder<String> subordinateHostnamesBuilder = new ImmutableSet.Builder<>(); ImmutableSet.Builder<String> subordinateHostnamesBuilder = new ImmutableSet.Builder<>();
String mainDomainName = String.format("domain%d.lol", numTotalDomainsPerActiveDomain); String mainDomainName = String.format("domain%d.lol", numTotalDomainsPerActiveDomain);
for (int i = numHosts; i >= 1; i--) { for (int i = numHosts; i >= 1; i--) {
@ -417,9 +418,9 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
subordinateHostnamesBuilder.add(hostName); subordinateHostnamesBuilder.add(hostName);
HostResource host = makeAndPersistHostResource( HostResource host = makeAndPersistHostResource(
hostName, String.format("5.5.%d.%d", 5 + i / 250, i % 250), clock.nowUtc().minusYears(1)); hostName, String.format("5.5.%d.%d", 5 + i / 250, i % 250), clock.nowUtc().minusYears(1));
hostKeysBuilder.add(Key.create(host)); hostKeysBuilder.add(host.createKey());
} }
ImmutableSet<Key<HostResource>> hostKeys = hostKeysBuilder.build(); ImmutableSet<VKey<HostResource>> hostKeys = hostKeysBuilder.build();
// Create all the domains at once, then persist them in parallel, for increased efficiency. // Create all the domains at once, then persist them in parallel, for increased efficiency.
ImmutableList.Builder<DomainBase> domainsBuilder = new ImmutableList.Builder<>(); ImmutableList.Builder<DomainBase> domainsBuilder = new ImmutableList.Builder<>();
for (int i = numActiveDomains * numTotalDomainsPerActiveDomain; i >= 1; i--) { for (int i = numActiveDomains * numTotalDomainsPerActiveDomain; i >= 1; i--) {

View file

@ -80,8 +80,8 @@ import org.junit.runners.JUnit4;
/** /**
* Unit tests for {@link DomainBaseToXjcConverter}. * Unit tests for {@link DomainBaseToXjcConverter}.
* *
* <p>This tests the mapping between {@link DomainBase} and {@link XjcRdeDomain} as well as * <p>This tests the mapping between {@link DomainBase} and {@link XjcRdeDomain} as well as some
* some exceptional conditions. * exceptional conditions.
*/ */
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class DomainBaseToXjcConverterTest { public class DomainBaseToXjcConverterTest {
@ -99,14 +99,12 @@ public class DomainBaseToXjcConverterTest {
@Test @Test
public void testConvertThick() { public void testConvertThick() {
XjcRdeDomain bean = XjcRdeDomain bean = DomainBaseToXjcConverter.convertDomain(makeDomainBase(clock), RdeMode.FULL);
DomainBaseToXjcConverter.convertDomain(makeDomainBase(clock), RdeMode.FULL);
assertThat(bean.getClID()).isEqualTo("GetTheeBack"); assertThat(bean.getClID()).isEqualTo("GetTheeBack");
assertThat( assertThat(
bean.getContacts() bean.getContacts().stream()
.stream()
.map(input -> String.format("%s %s", input.getType().toString(), input.getValue()))) .map(input -> String.format("%s %s", input.getType().toString(), input.getValue())))
.containsExactly("ADMIN 5372808-IRL", "TECH 5372808-TRL"); .containsExactly("ADMIN 5372808-IRL", "TECH 5372808-TRL");
@ -182,8 +180,7 @@ public class DomainBaseToXjcConverterTest {
@Test @Test
public void testConvertThin() { public void testConvertThin() {
XjcRdeDomain bean = XjcRdeDomain bean = DomainBaseToXjcConverter.convertDomain(makeDomainBase(clock), RdeMode.THIN);
DomainBaseToXjcConverter.convertDomain(makeDomainBase(clock), RdeMode.THIN);
assertThat(bean.getRegistrant()).isNull(); assertThat(bean.getRegistrant()).isNull();
assertThat(bean.getContacts()).isEmpty(); assertThat(bean.getContacts()).isEmpty();
assertThat(bean.getSecDNS()).isNull(); assertThat(bean.getSecDNS()).isNull();
@ -191,15 +188,13 @@ public class DomainBaseToXjcConverterTest {
@Test @Test
public void testMarshalThick() throws Exception { public void testMarshalThick() throws Exception {
XjcRdeDomain bean = XjcRdeDomain bean = DomainBaseToXjcConverter.convertDomain(makeDomainBase(clock), RdeMode.FULL);
DomainBaseToXjcConverter.convertDomain(makeDomainBase(clock), RdeMode.FULL);
wrapDeposit(bean).marshal(new ByteArrayOutputStream(), UTF_8); wrapDeposit(bean).marshal(new ByteArrayOutputStream(), UTF_8);
} }
@Test @Test
public void testMarshalThin() throws Exception { public void testMarshalThin() throws Exception {
XjcRdeDomain bean = XjcRdeDomain bean = DomainBaseToXjcConverter.convertDomain(makeDomainBase(clock), RdeMode.THIN);
DomainBaseToXjcConverter.convertDomain(makeDomainBase(clock), RdeMode.THIN);
wrapDeposit(bean).marshal(new ByteArrayOutputStream(), UTF_8); wrapDeposit(bean).marshal(new ByteArrayOutputStream(), UTF_8);
} }
@ -225,17 +220,18 @@ public class DomainBaseToXjcConverterTest {
newDomainBase("example.xn--q9jyb4c").asBuilder().setRepoId("2-Q9JYB4C").build(); newDomainBase("example.xn--q9jyb4c").asBuilder().setRepoId("2-Q9JYB4C").build();
HistoryEntry historyEntry = HistoryEntry historyEntry =
persistResource(new HistoryEntry.Builder().setParent(domain).build()); persistResource(new HistoryEntry.Builder().setParent(domain).build());
BillingEvent.OneTime billingEvent = persistResource( BillingEvent.OneTime billingEvent =
new BillingEvent.OneTime.Builder() persistResource(
.setReason(Reason.CREATE) new BillingEvent.OneTime.Builder()
.setTargetId("example.xn--q9jyb4c") .setReason(Reason.CREATE)
.setClientId("TheRegistrar") .setTargetId("example.xn--q9jyb4c")
.setCost(Money.of(USD, 26)) .setClientId("TheRegistrar")
.setPeriodYears(2) .setCost(Money.of(USD, 26))
.setEventTime(DateTime.parse("1910-01-01T00:00:00Z")) .setPeriodYears(2)
.setBillingTime(DateTime.parse("1910-01-01T00:00:00Z")) .setEventTime(DateTime.parse("1910-01-01T00:00:00Z"))
.setParent(historyEntry) .setBillingTime(DateTime.parse("1910-01-01T00:00:00Z"))
.build()); .setParent(historyEntry)
.build());
domain = domain =
domain domain
.asBuilder() .asBuilder()
@ -272,11 +268,10 @@ public class DomainBaseToXjcConverterTest {
.setLastEppUpdateTime(DateTime.parse("1920-01-01T00:00:00Z")) .setLastEppUpdateTime(DateTime.parse("1920-01-01T00:00:00Z"))
.setNameservers( .setNameservers(
ImmutableSet.of( ImmutableSet.of(
Key.create( makeHostResource(clock, "3-Q9JYB4C", "bird.or.devil.みんな", "1.2.3.4")
makeHostResource(clock, "3-Q9JYB4C", "bird.or.devil.みんな", "1.2.3.4")), .createKey(),
Key.create( makeHostResource(clock, "4-Q9JYB4C", "ns2.cat.みんな", "bad:f00d:cafe::15:beef")
makeHostResource( .createKey()))
clock, "4-Q9JYB4C", "ns2.cat.みんな", "bad:f00d:cafe::15:beef"))))
.setRegistrant( .setRegistrant(
Key.create( Key.create(
makeContactResource( makeContactResource(
@ -383,27 +378,24 @@ public class DomainBaseToXjcConverterTest {
.setPersistedCurrentSponsorClientId("GetTheeBack") .setPersistedCurrentSponsorClientId("GetTheeBack")
.setCreationClientId("GetTheeBack") .setCreationClientId("GetTheeBack")
.setCreationTimeForTest(END_OF_TIME) .setCreationTimeForTest(END_OF_TIME)
.setInternationalizedPostalInfo(new PostalInfo.Builder() .setInternationalizedPostalInfo(
.setType(PostalInfo.Type.INTERNATIONALIZED) new PostalInfo.Builder()
.setName(name) .setType(PostalInfo.Type.INTERNATIONALIZED)
.setOrg("SINNERS INCORPORATED") .setName(name)
.setAddress(new ContactAddress.Builder() .setOrg("SINNERS INCORPORATED")
.setStreet(ImmutableList.of("123 Example Boulevard")) .setAddress(
.setCity("KOKOMO") new ContactAddress.Builder()
.setState("BM") .setStreet(ImmutableList.of("123 Example Boulevard"))
.setZip("31337") .setCity("KOKOMO")
.setCountryCode("US") .setState("BM")
.setZip("31337")
.setCountryCode("US")
.build())
.build()) .build())
.build())
.setRepoId(repoId) .setRepoId(repoId)
.setVoiceNumber( .setVoiceNumber(
new ContactPhoneNumber.Builder() new ContactPhoneNumber.Builder().setPhoneNumber("+1.2126660420").build())
.setPhoneNumber("+1.2126660420") .setFaxNumber(new ContactPhoneNumber.Builder().setPhoneNumber("+1.2126660421").build())
.build())
.setFaxNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.2126660421")
.build())
.build()); .build());
} }

View file

@ -58,27 +58,30 @@ import org.joda.time.DateTime;
final class RdeFixtures { final class RdeFixtures {
static DomainBase makeDomainBase(FakeClock clock, String tld) { static DomainBase makeDomainBase(FakeClock clock, String tld) {
DomainBase domain = new DomainBase.Builder() DomainBase domain =
.setFullyQualifiedDomainName("example." + tld) new DomainBase.Builder()
.setRepoId(generateNewDomainRoid(tld)) .setFullyQualifiedDomainName("example." + tld)
.setRegistrant(Key.create( .setRepoId(generateNewDomainRoid(tld))
makeContactResource(clock, .setRegistrant(
"5372808-ERL", "(◕‿◕) nevermore", "prophet@evil.みんな"))) Key.create(
.build(); makeContactResource(
clock, "5372808-ERL", "(◕‿◕) nevermore", "prophet@evil.みんな")))
.build();
HistoryEntry historyEntry = HistoryEntry historyEntry =
persistResource(new HistoryEntry.Builder().setParent(domain).build()); persistResource(new HistoryEntry.Builder().setParent(domain).build());
clock.advanceOneMilli(); clock.advanceOneMilli();
BillingEvent.OneTime billingEvent = persistResourceWithCommitLog( BillingEvent.OneTime billingEvent =
new BillingEvent.OneTime.Builder() persistResourceWithCommitLog(
.setReason(Reason.CREATE) new BillingEvent.OneTime.Builder()
.setTargetId("example." + tld) .setReason(Reason.CREATE)
.setClientId("TheRegistrar") .setTargetId("example." + tld)
.setCost(Money.of(USD, 26)) .setClientId("TheRegistrar")
.setPeriodYears(2) .setCost(Money.of(USD, 26))
.setEventTime(DateTime.parse("1990-01-01T00:00:00Z")) .setPeriodYears(2)
.setBillingTime(DateTime.parse("1990-01-01T00:00:00Z")) .setEventTime(DateTime.parse("1990-01-01T00:00:00Z"))
.setParent(historyEntry) .setBillingTime(DateTime.parse("1990-01-01T00:00:00Z"))
.build()); .setParent(historyEntry)
.build());
domain = domain =
domain domain
.asBuilder() .asBuilder()
@ -114,8 +117,8 @@ final class RdeFixtures {
.setIdnTableName("extended_latin") .setIdnTableName("extended_latin")
.setNameservers( .setNameservers(
ImmutableSet.of( ImmutableSet.of(
Key.create(makeHostResource(clock, "bird.or.devil.みんな", "1.2.3.4")), makeHostResource(clock, "bird.or.devil.みんな", "1.2.3.4").createKey(),
Key.create(makeHostResource(clock, "ns2.cat.みんな", "bad:f00d:cafe::15:beef")))) makeHostResource(clock, "ns2.cat.みんな", "bad:f00d:cafe::15:beef").createKey()))
.setRegistrationExpirationTime(DateTime.parse("1994-01-01T00:00:00Z")) .setRegistrationExpirationTime(DateTime.parse("1994-01-01T00:00:00Z"))
.setGracePeriods( .setGracePeriods(
ImmutableSet.of( ImmutableSet.of(
@ -220,26 +223,23 @@ final class RdeFixtures {
.setPersistedCurrentSponsorClientId("GetTheeBack") .setPersistedCurrentSponsorClientId("GetTheeBack")
.setCreationClientId("GetTheeBack") .setCreationClientId("GetTheeBack")
.setCreationTimeForTest(clock.nowUtc()) .setCreationTimeForTest(clock.nowUtc())
.setInternationalizedPostalInfo(new PostalInfo.Builder() .setInternationalizedPostalInfo(
.setType(PostalInfo.Type.INTERNATIONALIZED) new PostalInfo.Builder()
.setName(name) .setType(PostalInfo.Type.INTERNATIONALIZED)
.setOrg("DOGE INCORPORATED") .setName(name)
.setAddress(new ContactAddress.Builder() .setOrg("DOGE INCORPORATED")
.setStreet(ImmutableList.of("123 Example Boulevard")) .setAddress(
.setCity("KOKOMO") new ContactAddress.Builder()
.setState("BM") .setStreet(ImmutableList.of("123 Example Boulevard"))
.setZip("31337") .setCity("KOKOMO")
.setCountryCode("US") .setState("BM")
.setZip("31337")
.setCountryCode("US")
.build())
.build()) .build())
.build())
.setVoiceNumber( .setVoiceNumber(
new ContactPhoneNumber.Builder() new ContactPhoneNumber.Builder().setPhoneNumber("+1.5558675309").build())
.setPhoneNumber("+1.5558675309") .setFaxNumber(new ContactPhoneNumber.Builder().setPhoneNumber("+1.5558675310").build())
.build())
.setFaxNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.5558675310")
.build())
.build()); .build());
} }

View file

@ -35,7 +35,6 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.net.MediaType; import com.google.common.net.MediaType;
import com.googlecode.objectify.Key;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.reporting.spec11.soy.Spec11EmailSoyInfo; import google.registry.reporting.spec11.soy.Spec11EmailSoyInfo;
@ -375,7 +374,9 @@ public class Spec11EmailUtilsTest {
private static DomainBase persistDomainWithHost(String domainName, HostResource host) { private static DomainBase persistDomainWithHost(String domainName, HostResource host) {
return persistResource( return persistResource(
newDomainBase(domainName).asBuilder().setNameservers(ImmutableSet.of(Key.create(host))) newDomainBase(domainName)
.asBuilder()
.setNameservers(ImmutableSet.of(host.createKey()))
.build()); .build());
} }
} }

View file

@ -123,28 +123,34 @@ public enum Fixture {
.build()); .build());
persistResource( persistResource(
newDomainBase("love.xn--q9jyb4c", justine).asBuilder() newDomainBase("love.xn--q9jyb4c", justine)
.setContacts(ImmutableSet.of( .asBuilder()
DesignatedContact.create(ADMIN, Key.create(robert)), .setContacts(
DesignatedContact.create(BILLING, Key.create(google)), ImmutableSet.of(
DesignatedContact.create(TECH, Key.create(justine)))) DesignatedContact.create(ADMIN, Key.create(robert)),
.setNameservers(ImmutableSet.of( DesignatedContact.create(BILLING, Key.create(google)),
Key.create(persistActiveHost("ns1.love.xn--q9jyb4c")), DesignatedContact.create(TECH, Key.create(justine))))
Key.create(persistActiveHost("ns2.love.xn--q9jyb4c")))) .setNameservers(
ImmutableSet.of(
persistActiveHost("ns1.love.xn--q9jyb4c").createKey(),
persistActiveHost("ns2.love.xn--q9jyb4c").createKey()))
.build()); .build());
persistResource( persistResource(
newDomainBase("moogle.example", justine).asBuilder() newDomainBase("moogle.example", justine)
.setContacts(ImmutableSet.of( .asBuilder()
DesignatedContact.create(ADMIN, Key.create(robert)), .setContacts(
DesignatedContact.create(BILLING, Key.create(google)), ImmutableSet.of(
DesignatedContact.create(TECH, Key.create(justine)))) DesignatedContact.create(ADMIN, Key.create(robert)),
.setNameservers(ImmutableSet.of( DesignatedContact.create(BILLING, Key.create(google)),
Key.create(persistActiveHost("ns1.linode.com")), DesignatedContact.create(TECH, Key.create(justine))))
Key.create(persistActiveHost("ns2.linode.com")), .setNameservers(
Key.create(persistActiveHost("ns3.linode.com")), ImmutableSet.of(
Key.create(persistActiveHost("ns4.linode.com")), persistActiveHost("ns1.linode.com").createKey(),
Key.create(persistActiveHost("ns5.linode.com")))) persistActiveHost("ns2.linode.com").createKey(),
persistActiveHost("ns3.linode.com").createKey(),
persistActiveHost("ns4.linode.com").createKey(),
persistActiveHost("ns5.linode.com").createKey()))
.build()); .build());
persistResource( persistResource(

View file

@ -138,7 +138,7 @@ public class DatastoreHelper {
public static DomainBase newDomainBase(String domainName, HostResource host) { public static DomainBase newDomainBase(String domainName, HostResource host) {
return newDomainBase(domainName) return newDomainBase(domainName)
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(host.createKey()))
.build(); .build();
} }

View file

@ -40,6 +40,7 @@ import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress; import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarContact; import google.registry.model.registrar.RegistrarContact;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.util.Idn; import google.registry.util.Idn;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.List; import java.util.List;
@ -374,12 +375,12 @@ public final class FullFieldsTestEntityHelper {
builder.setContacts(contactsBuilder.build()); builder.setContacts(contactsBuilder.build());
} }
if ((ns1 != null) || (ns2 != null)) { if ((ns1 != null) || (ns2 != null)) {
ImmutableSet.Builder<Key<HostResource>> nsBuilder = new ImmutableSet.Builder<>(); ImmutableSet.Builder<VKey<HostResource>> nsBuilder = new ImmutableSet.Builder<>();
if (ns1 != null) { if (ns1 != null) {
nsBuilder.add(Key.create(ns1)); nsBuilder.add(ns1.createKey());
} }
if (ns2 != null) { if (ns2 != null) {
nsBuilder.add(Key.create(ns2)); nsBuilder.add(ns2.createKey());
} }
builder.setNameservers(nsBuilder.build()); builder.setNameservers(nsBuilder.build());
} }

View file

@ -32,7 +32,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import com.googlecode.objectify.Key;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.secdns.DelegationSignerData; import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
@ -144,15 +143,23 @@ public class GenerateDnsReportCommandTest extends CommandTestCase<GenerateDnsRep
.build()); .build());
nameserver3 = persistActiveHost("ns1.google.com"); nameserver3 = persistActiveHost("ns1.google.com");
nameserver4 = persistActiveHost("ns2.google.com"); nameserver4 = persistActiveHost("ns2.google.com");
domain1 = persistResource(newDomainBase("example.xn--q9jyb4c").asBuilder() domain1 =
.setNameservers(ImmutableSet.of(Key.create(nameserver1), Key.create(nameserver2))) persistResource(
.setDsData(ImmutableSet.of( newDomainBase("example.xn--q9jyb4c")
DelegationSignerData.create(12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC")), .asBuilder()
DelegationSignerData.create(56789, 2, 4, base16().decode("69FD46E6C4A45C55D4AC")))) .setNameservers(ImmutableSet.of(nameserver1.createKey(), nameserver2.createKey()))
.build()); .setDsData(
persistResource(newDomainBase("foobar.xn--q9jyb4c").asBuilder() ImmutableSet.of(
.setNameservers(ImmutableSet.of(Key.create(nameserver3), Key.create(nameserver4))) DelegationSignerData.create(
.build()); 12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC")),
DelegationSignerData.create(
56789, 2, 4, base16().decode("69FD46E6C4A45C55D4AC"))))
.build());
persistResource(
newDomainBase("foobar.xn--q9jyb4c")
.asBuilder()
.setNameservers(ImmutableSet.of(nameserver3.createKey(), nameserver4.createKey()))
.build());
// Persist a domain in a different tld that should be ignored. // Persist a domain in a different tld that should be ignored.
persistActiveDomain("should-be-ignored.example"); persistActiveDomain("should-be-ignored.example");
} }

View file

@ -24,10 +24,10 @@ import static org.junit.Assert.assertThrows;
import com.beust.jcommander.ParameterException; import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.model.domain.secdns.DelegationSignerData; import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter; import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -53,9 +53,9 @@ public class UniformRapidSuspensionCommandTest
} }
private void persistDomainWithHosts(HostResource... hosts) { private void persistDomainWithHosts(HostResource... hosts) {
ImmutableSet.Builder<Key<HostResource>> hostRefs = new ImmutableSet.Builder<>(); ImmutableSet.Builder<VKey<HostResource>> hostRefs = new ImmutableSet.Builder<>();
for (HostResource host : hosts) { for (HostResource host : hosts) {
hostRefs.add(Key.create(host)); hostRefs.add(host.createKey());
} }
persistResource(newDomainBase("evil.tld").asBuilder() persistResource(newDomainBase("evil.tld").asBuilder()
.setNameservers(hostRefs.build()) .setNameservers(hostRefs.build())

View file

@ -31,6 +31,7 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact; import google.registry.model.domain.DesignatedContact;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import org.junit.Test; import org.junit.Test;
/** Unit tests for {@link UpdateDomainCommand}. */ /** Unit tests for {@link UpdateDomainCommand}. */
@ -116,12 +117,12 @@ public class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomain
persistResource( persistResource(
newDomainBase("example.abc") newDomainBase("example.abc")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host1))) .setNameservers(ImmutableSet.of(host1.createKey()))
.build()); .build());
persistResource( persistResource(
newDomainBase("example.tld") newDomainBase("example.tld")
.asBuilder() .asBuilder()
.setNameservers(ImmutableSet.of(Key.create(host2))) .setNameservers(ImmutableSet.of(host2.createKey()))
.build()); .build());
runCommandForced( runCommandForced(
"--client=NewRegistrar", nsParam, "example.abc", "example.tld"); "--client=NewRegistrar", nsParam, "example.abc", "example.tld");
@ -171,8 +172,8 @@ public class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomain
public void testSuccess_setNameservers() throws Exception { public void testSuccess_setNameservers() throws Exception {
HostResource host1 = persistActiveHost("ns1.zdns.google"); HostResource host1 = persistActiveHost("ns1.zdns.google");
HostResource host2 = persistActiveHost("ns2.zdns.google"); HostResource host2 = persistActiveHost("ns2.zdns.google");
ImmutableSet<Key<HostResource>> nameservers = ImmutableSet<VKey<HostResource>> nameservers =
ImmutableSet.of(Key.create(host1), Key.create(host2)); ImmutableSet.of(host1.createKey(), host2.createKey());
persistResource( persistResource(
newDomainBase("example.tld").asBuilder().setNameservers(nameservers).build()); newDomainBase("example.tld").asBuilder().setNameservers(nameservers).build());
runCommandForced( runCommandForced(
@ -213,7 +214,7 @@ public class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomain
@Test @Test
public void testSuccess_setStatuses() throws Exception { public void testSuccess_setStatuses() throws Exception {
HostResource host = persistActiveHost("ns1.zdns.google"); HostResource host = persistActiveHost("ns1.zdns.google");
ImmutableSet<Key<HostResource>> nameservers = ImmutableSet.of(Key.create(host)); ImmutableSet<VKey<HostResource>> nameservers = ImmutableSet.of(host.createKey());
persistResource( persistResource(
newDomainBase("example.tld") newDomainBase("example.tld")
.asBuilder() .asBuilder()
@ -257,7 +258,7 @@ public class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomain
@Test @Test
public void testFailure_cantUpdateRegistryLockedDomainEvenAsSuperuser() { public void testFailure_cantUpdateRegistryLockedDomainEvenAsSuperuser() {
HostResource host = persistActiveHost("ns1.zdns.google"); HostResource host = persistActiveHost("ns1.zdns.google");
ImmutableSet<Key<HostResource>> nameservers = ImmutableSet.of(Key.create(host)); ImmutableSet<VKey<HostResource>> nameservers = ImmutableSet.of(host.createKey());
persistResource( persistResource(
newDomainBase("example.tld") newDomainBase("example.tld")
.asBuilder() .asBuilder()

View file

@ -34,10 +34,10 @@ import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.model.domain.secdns.DelegationSignerData; import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import google.registry.testing.FakeClock; import google.registry.testing.FakeClock;
import google.registry.testing.mapreduce.MapreduceTestCase; import google.registry.testing.mapreduce.MapreduceTestCase;
import java.net.InetAddress; import java.net.InetAddress;
@ -67,8 +67,8 @@ public class GenerateZoneFilesActionTest extends MapreduceTestCase<GenerateZoneF
HostResource host2 = HostResource host2 =
persistResource(newHostResource("ns.bar.tld").asBuilder().addInetAddresses(ips).build()); persistResource(newHostResource("ns.bar.tld").asBuilder().addInetAddresses(ips).build());
ImmutableSet<Key<HostResource>> nameservers = ImmutableSet<VKey<HostResource>> nameservers =
ImmutableSet.of(Key.create(host1), Key.create(host2)); ImmutableSet.of(host1.createKey(), host2.createKey());
// This domain will have glue records, because it has a subordinate host which is its own // This domain will have glue records, because it has a subordinate host which is its own
// nameserver. None of the other domains should have glue records, because their nameservers are // nameserver. None of the other domains should have glue records, because their nameservers are
// subordinate to different domains. // subordinate to different domains.

View file

@ -37,6 +37,7 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.model.registrar.Registrar; import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarContact; import google.registry.model.registrar.RegistrarContact;
import google.registry.persistence.VKey;
import google.registry.testing.AppEngineRule; import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeClock; import google.registry.testing.FakeClock;
import google.registry.whois.WhoisResponse.WhoisResponseResults; import google.registry.whois.WhoisResponse.WhoisResponseResults;
@ -220,8 +221,8 @@ public class DomainWhoisResponseTest {
.setEmailAddress("EMAIL@EXAMPLE.tld") .setEmailAddress("EMAIL@EXAMPLE.tld")
.build()); .build());
Key<HostResource> hostResource1Key = Key.create(hostResource1); VKey<HostResource> hostResource1Key = hostResource1.createKey();
Key<HostResource> hostResource2Key = Key.create(hostResource2); VKey<HostResource> hostResource2Key = hostResource2.createKey();
Key<ContactResource> registrantResourceKey = Key.create(registrant); Key<ContactResource> registrantResourceKey = Key.create(registrant);
Key<ContactResource> adminResourceKey = Key.create(adminContact); Key<ContactResource> adminResourceKey = Key.create(adminContact);
Key<ContactResource> techResourceKey = Key.create(techContact); Key<ContactResource> techResourceKey = Key.create(techContact);