Switch from using raw HistoryEntries to typed subclasses thereof (#1150)

HistoryEntry is used to record all histories (contact, domain, host) in
Datastore. In SQL it is now split into three subclasses (and thus
tables): ContactHistory, DomainHistory and HostHistory. Its builder is
genericized as a result which led to a lot of compiler warnings for the
use of a raw HistoryEntry in the existing code base.

This PR cleans things up by replacing all the explicit use of
raw HistoryEntry with the corresponding subclass and also adds some
guardrails to prevent the use of raw HistoryEntry accidentally.

Note that because DomainHistory includes nsHosts and gracePeriodHistory,
both of which are assigned a roid from ofy when built, the assigned roids for
resources after history entries are built are incremented compared to
when only HistoryEntrys are built (before this PR) in
RdapDomainSearchActionTest.

Also added a convenient tm().updateAll() varargs method.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1150)
<!-- Reviewable:end -->
This commit is contained in:
Lai Jiang 2021-05-20 11:58:41 -04:00 committed by GitHub
parent f7dca7fa96
commit 02eb7cfcc3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 380 additions and 229 deletions

View file

@ -370,11 +370,10 @@ public class DeleteContactsAndHostsAction implements Runnable {
: "it was transferred prior to deletion");
HistoryEntry historyEntry =
new HistoryEntry.Builder()
HistoryEntry.createBuilderForResource(resource)
.setClientId(deletionRequest.requestingClientId())
.setModificationTime(now)
.setType(getHistoryEntryType(resource, deleteAllowed))
.setParent(deletionRequest.key())
.build();
PollMessage.OneTime pollMessage =
@ -409,7 +408,9 @@ public class DeleteContactsAndHostsAction implements Runnable {
} else {
resourceToSave = resource.asBuilder().removeStatusValue(PENDING_DELETE).build();
}
auditedOfy().save().<ImmutableObject>entities(resourceToSave, historyEntry, pollMessage);
auditedOfy()
.save()
.<ImmutableObject>entities(resourceToSave, historyEntry.asHistoryEntry(), pollMessage);
return DeletionResult.create(
deleteAllowed ? Type.DELETED : Type.NOT_DELETED, pollMessageText);
}

View file

@ -44,11 +44,11 @@ import google.registry.mapreduce.MapreduceRunner;
import google.registry.mapreduce.inputs.EppResourceInputs;
import google.registry.model.EppResourceUtils;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldType;
import google.registry.model.reporting.HistoryEntry;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.Response;
@ -253,9 +253,9 @@ public class DeleteProberDataAction implements Runnable {
.setDeletionTime(tm().getTransactionTime())
.setStatusValues(null)
.build();
HistoryEntry historyEntry =
new HistoryEntry.Builder()
.setParent(domain)
DomainHistory historyEntry =
new DomainHistory.Builder()
.setDomain(domain)
.setType(DOMAIN_DELETE)
.setModificationTime(tm().getTransactionTime())
.setBySuperuser(true)
@ -263,11 +263,9 @@ public class DeleteProberDataAction implements Runnable {
.setClientId(registryAdminClientId)
.build();
// Note that we don't bother handling grace periods, billing events, pending
// transfers,
// poll messages, or auto-renews because these will all be hard-deleted the next
// time the
// mapreduce runs anyway.
auditedOfy().save().entities(deletedDomain, historyEntry);
// transfers, poll messages, or auto-renews because these will all be hard-deleted
// the next time the mapreduce runs anyway.
tm().putAll(deletedDomain, historyEntry);
updateForeignKeyIndexDeletionTime(deletedDomain);
dnsQueue.addDomainRefreshTask(deletedDomain.getDomainName());
});

View file

@ -49,6 +49,7 @@ import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.common.Cursor;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.DomainTransactionRecord;
@ -188,12 +189,14 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
// an event persisted.
for (DateTime billingTime : difference(billingTimes, existingBillingTimes)) {
// Construct a new HistoryEntry that parents over the OneTime
HistoryEntry historyEntry =
new HistoryEntry.Builder()
DomainHistory historyEntry =
new DomainHistory.Builder()
.setBySuperuser(false)
.setClientId(recurring.getClientId())
.setModificationTime(tm().getTransactionTime())
.setParent(domainKey)
// TODO (jianglai): modify this to use setDomain instead when
// converting this action to be SQL-aware.
.setDomainRepoId(domainKey.getName())
.setPeriod(Period.create(1, YEARS))
.setReason(
"Domain autorenewal by ExpandRecurringBillingEventsAction")

View file

@ -213,50 +213,78 @@ public class FlowModule {
return Strings.nullToEmpty(((Poll) eppInput.getCommandWrapper().getCommand()).getMessageId());
}
private static <B extends HistoryEntry.Builder<? extends HistoryEntry, ?>>
B makeHistoryEntryBuilder(
B builder,
Trid trid,
byte[] inputXmlBytes,
boolean isSuperuser,
String clientId,
EppInput eppInput) {
builder
.setTrid(trid)
.setXmlBytes(inputXmlBytes)
.setBySuperuser(isSuperuser)
.setClientId(clientId);
Optional<MetadataExtension> metadataExtension =
eppInput.getSingleExtension(MetadataExtension.class);
metadataExtension.ifPresent(
extension ->
builder
.setReason(extension.getReason())
.setRequestedByRegistrar(extension.getRequestedByRegistrar()));
return builder;
}
/**
* Provides a partially filled in {@link HistoryEntry} builder.
* Provides a partially filled in {@link ContactHistory.Builder}
*
* <p>This is not marked with {@link FlowScope} so that each retry gets a fresh one. Otherwise,
* the fact that the builder is one-use would cause NPEs.
*/
@Provides
static HistoryEntry.Builder provideHistoryEntryBuilder(
static ContactHistory.Builder provideContactHistoryBuilder(
Trid trid,
@InputXml byte[] inputXmlBytes,
@Superuser boolean isSuperuser,
@ClientId String clientId,
EppInput eppInput) {
HistoryEntry.Builder historyBuilder =
new HistoryEntry.Builder()
.setTrid(trid)
.setXmlBytes(inputXmlBytes)
.setBySuperuser(isSuperuser)
.setClientId(clientId);
Optional<MetadataExtension> metadataExtension =
eppInput.getSingleExtension(MetadataExtension.class);
metadataExtension.ifPresent(
extension ->
historyBuilder
.setReason(extension.getReason())
.setRequestedByRegistrar(extension.getRequestedByRegistrar()));
return historyBuilder;
return makeHistoryEntryBuilder(
new ContactHistory.Builder(), trid, inputXmlBytes, isSuperuser, clientId, eppInput);
}
/**
* Provides a partially filled in {@link HostHistory.Builder}
*
* <p>This is not marked with {@link FlowScope} so that each retry gets a fresh one. Otherwise,
* the fact that the builder is one-use would cause NPEs.
*/
@Provides
static ContactHistory.Builder provideContactHistoryBuilder(
HistoryEntry.Builder historyEntryBuilder) {
return new ContactHistory.Builder().copyFrom(historyEntryBuilder);
static HostHistory.Builder provideHostHistoryBuilder(
Trid trid,
@InputXml byte[] inputXmlBytes,
@Superuser boolean isSuperuser,
@ClientId String clientId,
EppInput eppInput) {
return makeHistoryEntryBuilder(
new HostHistory.Builder(), trid, inputXmlBytes, isSuperuser, clientId, eppInput);
}
/**
* Provides a partially filled in {@link DomainHistory.Builder}
*
* <p>This is not marked with {@link FlowScope} so that each retry gets a fresh one. Otherwise,
* the fact that the builder is one-use would cause NPEs.
*/
@Provides
static DomainHistory.Builder provideDomainHistoryBuilder(
HistoryEntry.Builder historyEntryBuilder) {
return new DomainHistory.Builder().copyFrom(historyEntryBuilder);
}
@Provides
static HostHistory.Builder provideHostHistoryBuilder(HistoryEntry.Builder historyEntryBuilder) {
return new HostHistory.Builder().copyFrom(historyEntryBuilder);
Trid trid,
@InputXml byte[] inputXmlBytes,
@Superuser boolean isSuperuser,
@ClientId String clientId,
EppInput eppInput) {
return makeHistoryEntryBuilder(
new DomainHistory.Builder(), trid, inputXmlBytes, isSuperuser, clientId, eppInput);
}
/**

View file

@ -41,6 +41,11 @@ import javax.persistence.PostLoad;
* <p>In addition to the general history fields (e.g. action time, registrar ID) we also persist a
* copy of the contact entity at this point in time. We persist a raw {@link ContactBase} so that
* the foreign-keyed fields in that class can refer to this object.
*
* <p>This class is only marked as a Datastore entity subclass and registered with Objectify so that
* when building it its ID can be auto-populated by Objectify. It is converted to its superclass
* {@link HistoryEntry} when persisted to Datastore using {@link
* google.registry.persistence.transaction.TransactionManager}.
*/
@Entity
@javax.persistence.Table(

View file

@ -21,7 +21,6 @@ import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.EntitySubclass;
import com.googlecode.objectify.annotation.Ignore;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod.GracePeriodHistory;
@ -62,6 +61,11 @@ import javax.persistence.Table;
* <p>In addition to the general history fields (e.g. action time, registrar ID) we also persist a
* copy of the domain entity at this point in time. We persist a raw {@link DomainContent} so that
* the foreign-keyed fields in that class can refer to this object.
*
* <p>This class is only marked as a Datastore entity subclass and registered with Objectify so that
* when building it its ID can be auto-populated by Objectify. It is converted to its superclass
* {@link HistoryEntry} when persisted to Datastore using {@link
* google.registry.persistence.transaction.TransactionManager}.
*/
@Entity
@Table(
@ -97,7 +101,6 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
// We could have reused domainContent.nsHosts here, but Hibernate throws a weird exception after
// we change to use a composite primary key.
// TODO(b/166776754): Investigate if we can reuse domainContent.nsHosts for storing host keys.
@Ignore
@ElementCollection
@JoinTable(
name = "DomainHistoryHost",
@ -111,7 +114,6 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
@Column(name = "host_repo_id")
Set<VKey<HostResource>> nsHosts;
@Ignore
@OneToMany(
cascade = {CascadeType.ALL},
fetch = FetchType.EAGER,
@ -131,7 +133,6 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
// HashSet rather than ImmutableSet so that Hibernate can fill them out lazily on request
Set<DomainDsDataHistory> dsDataHistories = new HashSet<>();
@Ignore
@OneToMany(
cascade = {CascadeType.ALL},
fetch = FetchType.EAGER,

View file

@ -41,6 +41,11 @@ import javax.persistence.PostLoad;
* <p>In addition to the general history fields (e.g. action time, registrar ID) we also persist a
* copy of the host entity at this point in time. We persist a raw {@link HostBase} so that the
* foreign-keyed fields in that class can refer to this object.
*
* <p>This class is only marked as a Datastore entity subclass and registered with Objectify so that
* when building it its ID can be auto-populated by Objectify. It is converted to its superclass
* {@link HistoryEntry} when persisted to Datastore using {@link
* google.registry.persistence.transaction.TransactionManager}.
*/
@Entity
@javax.persistence.Table(

View file

@ -173,6 +173,11 @@ public class DatastoreTransactionManager implements TransactionManager {
putAll(entities);
}
@Override
public void updateAll(Object... entities) {
updateAll(ImmutableList.of(entities));
}
@Override
public void updateWithoutBackup(Object entity) {
putWithoutBackup(entity);

View file

@ -32,14 +32,17 @@ import google.registry.model.Buildable;
import google.registry.model.EppResource;
import google.registry.model.ImmutableObject;
import google.registry.model.annotations.ReportedOn;
import google.registry.model.contact.ContactBase;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactHistory.ContactHistoryId;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainContent;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.Period;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostBase;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostHistory.HostHistoryId;
import google.registry.model.host.HostResource;
@ -60,7 +63,21 @@ import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.joda.time.DateTime;
/** A record of an EPP command that mutated a resource. */
/**
* A record of an EPP command that mutated a resource.
*
* <p>Due to historical reasons this class is persisted only to Datastore. It has three subclasses
* that include the parent resource itself which are persisted to Cloud SQL. During migration this
* class cannot be made abstract in order for the class to be persisted and loaded to and from
* Datastore. However it should never be used directly in the Java code itself. When it is loaded
* from Datastore it should be converted to a subclass for handling and when a new history entry is
* built it should always be a subclass, which is automatically converted to HistoryEntry when
* persisting to Datastore.
*
* <p>Some care has been taken to make it close to impossible to use this class directly, but the
* user should still exercise caution. After the migration is complete this class will be made
* abstract.
*/
@ReportedOn
@Entity
@MappedSuperclass
@ -203,6 +220,12 @@ public class HistoryEntry extends ImmutableObject implements Buildable, Datastor
@ImmutableObject.EmptySetToNull
protected Set<DomainTransactionRecord> domainTransactionRecords;
// Make it impossible to instantiate a HistoryEntry explicitly. One should only instantiate a
// subtype of HistoryEntry.
protected HistoryEntry() {
super();
}
public long getId() {
// For some reason, Hibernate throws NPE during some initialization phase if we don't deal with
// the null case. Setting the id to 0L when it is null should be fine because 0L for primitive
@ -285,13 +308,50 @@ public class HistoryEntry extends ImmutableObject implements Buildable, Datastor
domainTransactionRecords == null ? null : ImmutableSet.copyOf(domainTransactionRecords);
}
/**
* Throws an error when trying to get a builder from a bare {@link HistoryEntry}.
*
* <p>This method only exists to satisfy the requirement that the {@link HistoryEntry} is NOT
* abstract, it should never be called directly and all three of the subclass of {@link
* HistoryEntry} implements it.
*/
@Override
public Builder asBuilder() {
return new Builder(clone(this));
public Builder<? extends HistoryEntry, ?> asBuilder() {
throw new UnsupportedOperationException(
"You should never attempt to build a HistoryEntry from a raw HistoryEntry. A raw "
+ "HistoryEntry should only exist internally when persisting to datastore. If you need "
+ "to build from a raw HistoryEntry, use "
+ "{Contact,Host,Domain}History.Builder.copyFrom(HistoryEntry) instead.");
}
/**
* Clones and returns a {@code HistoryEntry} objec
*
* <p>This is useful when converting a subclass to the base class to persist to Datastore.
*/
public HistoryEntry asHistoryEntry() {
return new Builder().copyFrom(this).build();
HistoryEntry historyEntry = new HistoryEntry();
copy(this, historyEntry);
return historyEntry;
}
protected static void copy(HistoryEntry src, HistoryEntry dst) {
dst.id = src.id;
dst.parent = src.parent;
dst.type = src.type;
dst.period = src.period;
dst.xmlBytes = src.xmlBytes;
dst.modificationTime = src.modificationTime;
dst.clientId = src.clientId;
dst.otherClientId = src.otherClientId;
dst.trid = src.trid;
dst.bySuperuser = src.bySuperuser;
dst.reason = src.reason;
dst.requestedByRegistrar = src.requestedByRegistrar;
dst.domainTransactionRecords =
src.domainTransactionRecords == null
? null
: ImmutableSet.copyOf(src.domainTransactionRecords);
}
@SuppressWarnings("unchecked")
@ -349,33 +409,18 @@ public class HistoryEntry extends ImmutableObject implements Buildable, Datastor
}
/** A builder for {@link HistoryEntry} since it is immutable */
public static class Builder<T extends HistoryEntry, B extends Builder<?, ?>>
public abstract static class Builder<T extends HistoryEntry, B extends Builder<?, ?>>
extends GenericBuilder<T, B> {
public Builder() {}
protected Builder() {}
public Builder(T instance) {
protected Builder(T instance) {
super(instance);
}
// Used to fill out the fields in this object from an object which may not be exactly the same
// as the class T, where both classes still subclass HistoryEntry
public B copyFrom(HistoryEntry historyEntry) {
setId(historyEntry.id);
setParent(historyEntry.parent);
setType(historyEntry.type);
setPeriod(historyEntry.period);
setXmlBytes(historyEntry.xmlBytes);
setModificationTime(historyEntry.modificationTime);
setClientId(historyEntry.clientId);
setOtherClientId(historyEntry.otherClientId);
setTrid(historyEntry.trid);
setBySuperuser(historyEntry.bySuperuser);
setReason(historyEntry.reason);
setRequestedByRegistrar(historyEntry.requestedByRegistrar);
setDomainTransactionRecords(
historyEntry.domainTransactionRecords == null
? null
: ImmutableSet.copyOf(historyEntry.domainTransactionRecords));
copy(historyEntry, getInstance());
return thisCastToDerived();
}
@ -400,13 +445,13 @@ public class HistoryEntry extends ImmutableObject implements Buildable, Datastor
return thisCastToDerived();
}
public B setParent(EppResource parent) {
protected B setParent(EppResource parent) {
getInstance().parent = Key.create(parent);
return thisCastToDerived();
}
// Until we move completely to SQL, override this in subclasses (e.g. HostHistory) to set VKeys
public B setParent(Key<? extends EppResource> parent) {
protected B setParent(Key<? extends EppResource> parent) {
getInstance().parent = parent;
return thisCastToDerived();
}
@ -467,4 +512,19 @@ public class HistoryEntry extends ImmutableObject implements Buildable, Datastor
return thisCastToDerived();
}
}
public static <E extends EppResource>
HistoryEntry.Builder<? extends HistoryEntry, ?> createBuilderForResource(E parent) {
if (parent instanceof DomainContent) {
return new DomainHistory.Builder().setDomain((DomainContent) parent);
} else if (parent instanceof ContactBase) {
return new ContactHistory.Builder().setContact((ContactBase) parent);
} else if (parent instanceof HostBase) {
return new HostHistory.Builder().setHost((HostBase) parent);
} else {
throw new IllegalStateException(
String.format(
"Class %s does not have an associated HistoryEntry", parent.getClass().getName()));
}
}
}

View file

@ -350,6 +350,11 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
entities.forEach(this::update);
}
@Override
public void updateAll(Object... entities) {
updateAll(ImmutableList.of(entities));
}
@Override
public void updateWithoutBackup(Object entity) {
update(entity);

View file

@ -159,6 +159,9 @@ public interface TransactionManager {
/** Updates all entities in the database, throws exception if any entity does not exist. */
void updateAll(ImmutableCollection<?> entities);
/** Updates all entities in the database, throws exception if any entity does not exist. */
void updateAll(Object... entities);
/**
* Updates an entity in the database without writing commit logs if the underlying database is
* Datastore.

View file

@ -22,7 +22,6 @@ import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STAT
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.googlecode.objectify.Key;
import google.registry.batch.AsyncTaskEnqueuer;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.billing.BillingEvent;
@ -370,7 +369,7 @@ public final class DomainLockUtils {
.setRequestedByRegistrar(!lock.isSuperuser())
.setType(HistoryEntry.Type.DOMAIN_UPDATE)
.setModificationTime(now)
.setParent(Key.create(domain))
.setDomain(domain)
.setReason(reason)
.build();
tm().update(domain);

View file

@ -185,7 +185,7 @@ class UnrenewDomainCommand extends ConfirmingCommand implements CommandWithRemot
leapSafeSubtractYears(domain.getRegistrationExpirationTime(), period);
DomainHistory domainHistory =
new DomainHistory.Builder()
.setParent(domain)
.setDomain(domain)
.setModificationTime(now)
.setBySuperuser(true)
.setType(Type.SYNTHETIC)

View file

@ -113,12 +113,11 @@ public class CreateSyntheticHistoryEntriesAction implements Runnable {
() -> {
EppResource eppResource = ofy().load().key(resourceKey).now();
tm().put(
new HistoryEntry.Builder<>()
HistoryEntry.createBuilderForResource(eppResource)
.setClientId(registryAdminRegistrarId)
.setBySuperuser(true)
.setRequestedByRegistrar(false)
.setModificationTime(tm().getTransactionTime())
.setParent(eppResource)
.setReason(
"Backfill EppResource history objects during Cloud SQL migration")
.setType(HistoryEntry.Type.SYNTHETIC)

View file

@ -33,6 +33,7 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.ofy.Ofy;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
@ -166,9 +167,9 @@ class DeleteExpiredDomainsActionTest {
DomainBase pendingExpirationDomain = persistActiveDomain(domainName);
HistoryEntry createHistoryEntry =
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setType(DOMAIN_CREATE)
.setParent(pendingExpirationDomain)
.setDomain(pendingExpirationDomain)
.setModificationTime(clock.nowUtc().minusMonths(9))
.setClientId(pendingExpirationDomain.getCreationClientId())
.build());

View file

@ -39,6 +39,7 @@ import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.poll.PollMessage;
@ -281,8 +282,8 @@ class DeleteProberDataActionTest extends MapreduceTestCase<DeleteProberDataActio
DomainBase domain = persistDeletedDomain(fqdn, DELETION_TIME);
HistoryEntry historyEntry =
persistSimpleResource(
new HistoryEntry.Builder()
.setParent(domain)
new DomainHistory.Builder()
.setDomain(domain)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setClientId("TheRegistrar")
.setModificationTime(DELETION_TIME.minusYears(3))

View file

@ -45,6 +45,7 @@ import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.common.Cursor;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
import google.registry.model.ofy.Ofy;
import google.registry.model.registry.Registry;
@ -93,11 +94,11 @@ public class ExpandRecurringBillingEventsActionTest
.build());
historyEntry =
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setClientId(domain.getCreationClientId())
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(DateTime.parse("1999-01-05T00:00:00Z"))
.setParent(domain)
.setDomain(domain)
.build());
recurring =
new BillingEvent.Recurring.Builder()
@ -188,8 +189,8 @@ public class ExpandRecurringBillingEventsActionTest
DomainBase deletedDomain = persistDeletedDomain("deleted.tld", deletionTime);
historyEntry =
persistResource(
new HistoryEntry.Builder()
.setParent(deletedDomain)
new DomainHistory.Builder()
.setDomain(deletedDomain)
.setClientId(deletedDomain.getCreationClientId())
.setModificationTime(deletedDomain.getCreationTime())
.setType(DOMAIN_CREATE)

View file

@ -32,6 +32,7 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.rgp.GracePeriodStatus;
@ -102,8 +103,8 @@ public class DomainBaseUtilTest {
Key<HistoryEntry> historyEntryKey =
Key.create(
persistResource(
new HistoryEntry.Builder()
.setParent(domainKey)
new DomainHistory.Builder()
.setDomainRepoId(domainKey.getName())
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setClientId("TheRegistrar")
.setModificationTime(fakeClock.nowUtc().minusYears(1))

View file

@ -38,6 +38,7 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.rgp.GracePeriodStatus;
@ -178,8 +179,8 @@ class InitSqlPipelineTest {
.build());
historyEntry =
persistResource(
new HistoryEntry.Builder()
.setParent(domainKey)
new DomainHistory.Builder()
.setDomainRepoId(domainKey.getName())
.setModificationTime(fakeClock.nowUtc())
.setClientId(registrar1.getClientId())
.setType(HistoryEntry.Type.DOMAIN_CREATE)

View file

@ -84,6 +84,7 @@ import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
@ -121,7 +122,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
final ReplayExtension replayExtension = ReplayExtension.createWithCompare(clock);
private DomainBase domain;
private HistoryEntry earlierHistoryEntry;
private DomainHistory earlierHistoryEntry;
private static final DateTime TIME_BEFORE_FLOW = DateTime.parse("2000-06-06T22:00:00.0Z");
private static final DateTime A_MONTH_AGO = TIME_BEFORE_FLOW.minusMonths(1);
@ -175,9 +176,9 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.build());
earlierHistoryEntry =
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setType(DOMAIN_CREATE)
.setParent(domain)
.setDomain(domain)
.setModificationTime(clock.nowUtc())
.setClientId(domain.getCreationClientId())
.build());
@ -1111,9 +1112,9 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
DomainTransactionRecord.create("tld", TIME_BEFORE_FLOW.plusDays(2), NET_ADDS_10_YR, 1);
// Create a HistoryEntry with a later modification time
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setType(DOMAIN_CREATE)
.setParent(domain)
.setDomain(domain)
.setModificationTime(TIME_BEFORE_FLOW.minusDays(1))
.setClientId("TheRegistrar")
.setDomainTransactionRecords(ImmutableSet.of(existingRecord))

View file

@ -54,6 +54,7 @@ import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DelegationSignerData;
@ -362,8 +363,8 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
persistTestEntities(false);
HistoryEntry historyEntry =
persistResource(
new HistoryEntry.Builder()
.setParent(domain)
new DomainHistory.Builder()
.setDomain(domain)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(clock.nowUtc())
.setClientId(domain.getCreationClientId())

View file

@ -127,7 +127,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
try {
DomainHistory historyEntryDomainCreate =
new DomainHistory.Builder()
.setParent(domain)
.setDomain(domain)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(clock.nowUtc())
.setClientId(domain.getCreationClientId())

View file

@ -61,6 +61,7 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.StatusValue;
@ -113,11 +114,11 @@ class DomainRestoreRequestFlowTest
DomainBase domain = persistResource(newDomainBase(getUniqueIdFromCommand()));
HistoryEntry historyEntry =
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setType(HistoryEntry.Type.DOMAIN_DELETE)
.setModificationTime(clock.nowUtc())
.setClientId(domain.getCurrentSponsorClientId())
.setParent(domain)
.setDomain(domain)
.build());
persistResource(
domain

View file

@ -55,6 +55,7 @@ import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period;
import google.registry.model.domain.Period.Unit;
@ -603,9 +604,9 @@ class DomainTransferApproveFlowTest
DomainTransactionRecord notCancellableRecord =
DomainTransactionRecord.create("tld", clock.nowUtc().plusDays(1), NET_ADDS_4_YR, 5);
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setType(DOMAIN_TRANSFER_REQUEST)
.setParent(domain)
.setDomain(domain)
.setModificationTime(clock.nowUtc().minusDays(4))
.setClientId("TheRegistrar")
.setDomainTransactionRecords(

View file

@ -45,6 +45,7 @@ import google.registry.flows.exceptions.NotPendingTransferException;
import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
import google.registry.model.eppcommon.Trid;
@ -367,9 +368,9 @@ class DomainTransferRejectFlowTest
DomainTransactionRecord notCancellableRecord =
DomainTransactionRecord.create("tld", clock.nowUtc().plusDays(1), NET_RENEWS_3_YR, 5);
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setType(DOMAIN_TRANSFER_REQUEST)
.setParent(domain)
.setDomain(domain)
.setModificationTime(clock.nowUtc().minusDays(4))
.setClientId("TheRegistrar")
.setDomainTransactionRecords(

View file

@ -84,6 +84,7 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource;
@ -153,11 +154,11 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.setNameservers(ImmutableSet.of(host.createVKey()))
.build());
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(clock.nowUtc())
.setClientId(domain.getCreationClientId())
.setParent(domain)
.setDomain(domain)
.build());
clock.advanceOneMilli();
return domain;
@ -177,11 +178,11 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.setNameservers(ImmutableSet.of(host.createVKey()))
.build());
persistResource(
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(clock.nowUtc())
.setClientId(domain.getCreationClientId())
.setParent(domain)
.setDomain(domain)
.build());
clock.advanceOneMilli();
return domain;

View file

@ -28,9 +28,11 @@ import com.google.common.collect.ImmutableList;
import google.registry.flows.EppException;
import google.registry.flows.FlowTestCase;
import google.registry.flows.poll.PollRequestFlow.UnexpectedMessageIdException;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostResource;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
@ -210,11 +212,11 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
// response data block is produced in the poll message.
HistoryEntry historyEntry =
persistResource(
new HistoryEntry.Builder()
new ContactHistory.Builder()
.setClientId("NewRegistrar")
.setModificationTime(clock.nowUtc().minusDays(1))
.setType(HistoryEntry.Type.CONTACT_DELETE)
.setParent(contact)
.setContact(contact)
.build());
persistResource(
new PollMessage.OneTime.Builder()
@ -233,11 +235,11 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
// response data block is produced in the poll message.
HistoryEntry historyEntry =
persistResource(
new HistoryEntry.Builder()
new HostHistory.Builder()
.setClientId("NewRegistrar")
.setModificationTime(clock.nowUtc().minusDays(1))
.setType(HistoryEntry.Type.HOST_DELETE)
.setParent(host)
.setHost(host)
.build());
persistResource(
new PollMessage.OneTime.Builder()

View file

@ -441,7 +441,6 @@ public class DomainBaseSqlTest {
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(Period.create(1, Period.Unit.YEARS))
.setModificationTime(DateTime.now(UTC))
.setParent(Key.create(DomainBase.class, "4-COM"))
.setDomainRepoId("4-COM")
.setClientId("registrar1")
// These are non-null, but I don't think some tests set them.
@ -572,7 +571,6 @@ public class DomainBaseSqlTest {
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(Period.create(1, Period.Unit.YEARS))
.setModificationTime(DateTime.now(UTC))
.setParent(Key.create(DomainBase.class, "4-COM"))
.setDomainRepoId("4-COM")
.setClientId("registrar1")
// These are non-null, but I don't think some tests set them.

View file

@ -100,8 +100,8 @@ public class DomainBaseTest extends EntityTestCase {
historyEntryKey =
Key.create(
persistResource(
new HistoryEntry.Builder()
.setParent(domainKey.getOfyKey())
new DomainHistory.Builder()
.setDomainRepoId(domainKey.getOfyKey().getName())
.setModificationTime(fakeClock.nowUtc())
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setClientId("aregistrar")
@ -364,8 +364,8 @@ public class DomainBaseTest extends EntityTestCase {
private void doExpiredTransferTest(DateTime oldExpirationTime) {
HistoryEntry historyEntry =
new HistoryEntry.Builder()
.setParent(domain)
new DomainHistory.Builder()
.setDomain(domain)
.setModificationTime(fakeClock.nowUtc())
.setClientId(domain.getCurrentSponsorClientId())
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST)

View file

@ -207,9 +207,8 @@ public class LegacyHistoryObjectTest extends EntityTestCase {
.build();
}
private HistoryEntry.Builder historyEntryBuilderFor(EppResource parent) {
return new HistoryEntry.Builder()
.setParent(parent)
private HistoryEntry.Builder<?, ?> historyEntryBuilderFor(EppResource parent) {
return HistoryEntry.createBuilderForResource(parent)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(fakeClock.nowUtc())

View file

@ -17,6 +17,7 @@ package google.registry.model.ofy;
import static com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
import static google.registry.model.ofy.Ofy.getBaseEntityClassFromEntityOrKey;
@ -40,6 +41,7 @@ import com.googlecode.objectify.annotation.OnLoad;
import com.googlecode.objectify.annotation.OnSave;
import com.googlecode.objectify.annotation.Parent;
import google.registry.model.ImmutableObject;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.eppcommon.Trid;
@ -70,11 +72,11 @@ public class OfyTest {
void beforeEach() {
createTld("tld");
someObject =
new HistoryEntry.Builder()
new ContactHistory.Builder()
.setClientId("clientid")
.setModificationTime(START_OF_TIME)
.setType(HistoryEntry.Type.CONTACT_CREATE)
.setParent(persistActiveContact("parentContact"))
.setContact(persistActiveContact("parentContact"))
.setTrid(Trid.create("client", "server"))
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.build();
@ -99,7 +101,8 @@ public class OfyTest {
@Test
void testBackupGroupRootTimestampsMustIncreaseOnSave() {
doBackupGroupRootTimestampInversionTest(() -> auditedOfy().save().entity(someObject));
doBackupGroupRootTimestampInversionTest(
() -> auditedOfy().save().entity(someObject.asHistoryEntry()));
}
@Test
@ -115,8 +118,8 @@ public class OfyTest {
() ->
tm().transact(
() -> {
auditedOfy().save().entity(someObject);
auditedOfy().save().entity(someObject);
auditedOfy().save().entity(someObject.asHistoryEntry());
auditedOfy().save().entity(someObject.asHistoryEntry());
}));
assertThat(thrown).hasMessageThat().contains("Multiple entries with same key");
}
@ -143,7 +146,7 @@ public class OfyTest {
() ->
tm().transact(
() -> {
auditedOfy().save().entity(someObject);
auditedOfy().save().entity(someObject.asHistoryEntry());
auditedOfy().delete().entity(someObject);
}));
assertThat(thrown).hasMessageThat().contains("Multiple entries with same key");
@ -158,7 +161,7 @@ public class OfyTest {
tm().transact(
() -> {
auditedOfy().delete().entity(someObject);
auditedOfy().save().entity(someObject);
auditedOfy().save().entity(someObject.asHistoryEntry());
}));
assertThat(thrown).hasMessageThat().contains("Multiple entries with same key");
}
@ -288,7 +291,7 @@ public class OfyTest {
public Integer get() {
// There will be something in the manifest now, but it won't be committed if
// we throw.
auditedOfy().save().entity(someObject);
auditedOfy().save().entity(someObject.asHistoryEntry());
count++;
if (count == 3) {
return count;
@ -310,7 +313,7 @@ public class OfyTest {
public Void get() {
if (firstCallToVrun) {
firstCallToVrun = false;
auditedOfy().save().entity(someObject);
auditedOfy().save().entity(someObject.asHistoryEntry());
return null;
}
fail("Shouldn't have retried.");
@ -409,24 +412,26 @@ public class OfyTest {
@Test
void test_doWithFreshSessionCache() {
auditedOfy().saveWithoutBackup().entity(someObject).now();
auditedOfy().saveWithoutBackup().entity(someObject.asHistoryEntry()).now();
final HistoryEntry modifiedObject =
someObject.asBuilder().setModificationTime(END_OF_TIME).build();
// Mutate the saved objected, bypassing the Objectify session cache.
getDatastoreService().put(auditedOfy().saveWithoutBackup().toEntity(modifiedObject));
getDatastoreService()
.put(auditedOfy().saveWithoutBackup().toEntity(modifiedObject.asHistoryEntry()));
// Normal loading should come from the session cache and shouldn't reflect the mutation.
assertThat(auditedOfy().load().entity(someObject).now()).isEqualTo(someObject);
assertThat(auditedOfy().load().entity(someObject).now()).isEqualTo(someObject.asHistoryEntry());
// Loading inside doWithFreshSessionCache() should reflect the mutation.
boolean ran =
auditedOfy()
.doWithFreshSessionCache(
() -> {
assertThat(auditedOfy().load().entity(someObject).now())
.isEqualTo(modifiedObject);
assertAboutImmutableObjects()
.that(auditedOfy().load().entity(someObject).now())
.isEqualExceptFields(modifiedObject, "contactBase");
return true;
});
assertThat(ran).isTrue();
// Test the normal loading again to verify that we've restored the original session unchanged.
assertThat(auditedOfy().load().entity(someObject).now()).isEqualTo(someObject);
assertThat(auditedOfy().load().entity(someObject).now()).isEqualTo(someObject.asHistoryEntry());
}
}

View file

@ -26,6 +26,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import google.registry.model.EntityTestCase;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
import google.registry.model.eppcommon.Trid;
import google.registry.model.reporting.HistoryEntry;
@ -56,8 +57,8 @@ public class PollMessageTest extends EntityTestCase {
domain = persistResource(newDomainBase("foo.foobar", contact));
historyEntry =
persistResource(
new HistoryEntry.Builder()
.setParent(domain)
new DomainHistory.Builder()
.setDomain(domain)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(Period.create(1, Period.Unit.YEARS))
.setXmlBytes("<xml></xml>".getBytes(UTF_8))

View file

@ -27,6 +27,7 @@ import static org.junit.Assert.assertThrows;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import google.registry.model.EntityTestCase;
import google.registry.model.contact.ContactHistory;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
@ -96,7 +97,7 @@ class HistoryEntryTest extends EntityTestCase {
assertThrows(
IllegalArgumentException.class,
() ->
new HistoryEntry.Builder()
new ContactHistory.Builder()
.setId(5L)
.setModificationTime(DateTime.parse("1985-07-12T22:30:00Z"))
.setClientId("TheRegistrar")
@ -111,7 +112,7 @@ class HistoryEntryTest extends EntityTestCase {
assertThrows(
IllegalArgumentException.class,
() ->
new HistoryEntry.Builder()
new ContactHistory.Builder()
.setId(5L)
.setType(HistoryEntry.Type.CONTACT_CREATE)
.setClientId("TheRegistrar")
@ -126,7 +127,7 @@ class HistoryEntryTest extends EntityTestCase {
assertThrows(
IllegalArgumentException.class,
() ->
new HistoryEntry.Builder()
new ContactHistory.Builder()
.setId(5L)
.setType(HistoryEntry.Type.CONTACT_CREATE)
.setModificationTime(DateTime.parse("1985-07-12T22:30:00Z"))
@ -141,7 +142,7 @@ class HistoryEntryTest extends EntityTestCase {
assertThrows(
IllegalArgumentException.class,
() ->
new HistoryEntry.Builder()
new ContactHistory.Builder()
.setId(5L)
.setType(HistoryEntry.Type.SYNTHETIC)
.setModificationTime(DateTime.parse("1985-07-12T22:30:00Z"))

View file

@ -1147,9 +1147,9 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
assertThat(generateActualJson(RequestType.NAME, "domain*.lol"))
.isEqualTo(
jsonFileBuilder()
.addDomain("domain100.lol", "A7-LOL")
.addDomain("domain150.lol", "75-LOL")
.addDomain("domain200.lol", "43-LOL")
.addDomain("domain100.lol", "AC-LOL")
.addDomain("domain150.lol", "7A-LOL")
.addDomain("domain200.lol", "48-LOL")
.addDomain("domainunused.lol", "unused-LOL")
.load("rdap_incomplete_domain_result_set.json"));
assertThat(response.getStatus()).isEqualTo(200);
@ -1165,10 +1165,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NAME,
"domain*.lol",
"46-LOL",
"45-LOL",
"44-LOL",
"43-LOL",
"4B-LOL",
"4A-LOL",
"49-LOL",
"48-LOL",
"rdap_nontruncated_domains.json");
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(4L));
}
@ -1179,10 +1179,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NAME,
"domain*.lol",
"47-LOL",
"46-LOL",
"45-LOL",
"44-LOL",
"4C-LOL",
"4B-LOL",
"4A-LOL",
"49-LOL",
"name=domain*.lol&cursor=ZG9tYWluNC5sb2w%3D",
"rdap_domains_four_truncated.json");
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(5L), IncompletenessWarningType.TRUNCATED);
@ -1197,8 +1197,8 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
jsonFileBuilder()
.addDomain("cat.lol", "C-LOL")
.addDomain("cat2.lol", "17-LOL")
.addDomain("domain1.lol", "46-LOL")
.addDomain("domain2.lol", "45-LOL")
.addDomain("domain1.lol", "4B-LOL")
.addDomain("domain2.lol", "4A-LOL")
.setNextQuery("name=*.lol&cursor=ZG9tYWluMi5sb2w%3D")
.load("rdap_domains_four_truncated.json"));
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(5L), IncompletenessWarningType.TRUNCATED);
@ -1213,8 +1213,8 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
jsonFileBuilder()
.addDomain("cat2.lol", "17-LOL")
.addDomain("cat.lol", "C-LOL")
.addDomain("domain1.lol", "46-LOL")
.addDomain("domain2.lol", "45-LOL")
.addDomain("domain1.lol", "4B-LOL")
.addDomain("domain2.lol", "4A-LOL")
.setNextQuery("name=*.lol&cursor=ZG9tYWluMi5sb2w%3D")
.load("rdap_domains_four_truncated.json"));
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(5L), IncompletenessWarningType.TRUNCATED);
@ -1228,10 +1228,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NAME,
"domain*.lol",
"4B-LOL",
"4A-LOL",
"49-LOL",
"48-LOL",
"50-LOL",
"4F-LOL",
"4E-LOL",
"4D-LOL",
"name=domain*.lol&cursor=ZG9tYWluNC5sb2w%3D",
"rdap_domains_four_truncated.json");
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(5L), IncompletenessWarningType.TRUNCATED);
@ -1244,10 +1244,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
assertThat(generateActualJson(RequestType.NAME, "domain*.lol"))
.isEqualTo(
jsonFileBuilder()
.addDomain("domain12.lol", "55-LOL")
.addDomain("domain18.lol", "4F-LOL")
.addDomain("domain24.lol", "49-LOL")
.addDomain("domain30.lol", "43-LOL")
.addDomain("domain12.lol", "5A-LOL")
.addDomain("domain18.lol", "54-LOL")
.addDomain("domain24.lol", "4E-LOL")
.addDomain("domain30.lol", "48-LOL")
.setNextQuery("name=domain*.lol&cursor=ZG9tYWluMzAubG9s")
.load("rdap_domains_four_truncated.json"));
assertThat(response.getStatus()).isEqualTo(200);
@ -1261,10 +1261,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
assertThat(generateActualJson(RequestType.NAME, "domain*.lol"))
.isEqualTo(
jsonFileBuilder()
.addDomain("domain12.lol", "55-LOL")
.addDomain("domain18.lol", "4F-LOL")
.addDomain("domain24.lol", "49-LOL")
.addDomain("domain30.lol", "43-LOL")
.addDomain("domain12.lol", "5A-LOL")
.addDomain("domain18.lol", "54-LOL")
.addDomain("domain24.lol", "4E-LOL")
.addDomain("domain30.lol", "48-LOL")
.setNextQuery("name=domain*.lol&cursor=ZG9tYWluMzAubG9s")
.load("rdap_domains_four_truncated.json"));
assertThat(response.getStatus()).isEqualTo(200);
@ -1672,10 +1672,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NS_LDH_NAME,
"ns1.domain1.lol",
"46-LOL",
"45-LOL",
"44-LOL",
"43-LOL",
"4B-LOL",
"4A-LOL",
"49-LOL",
"48-LOL",
"rdap_nontruncated_domains.json");
verifyMetrics(SearchType.BY_NAMESERVER_NAME, Optional.of(4L), Optional.of(1L));
}
@ -1686,10 +1686,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NS_LDH_NAME,
"ns1.domain1.lol",
"47-LOL",
"46-LOL",
"45-LOL",
"44-LOL",
"4C-LOL",
"4B-LOL",
"4A-LOL",
"49-LOL",
"nsLdhName=ns1.domain1.lol&cursor=ZG9tYWluNC5sb2w%3D",
"rdap_domains_four_truncated.json");
verifyMetrics(
@ -1705,10 +1705,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NS_LDH_NAME,
"ns1.domain1.lol",
"4B-LOL",
"4A-LOL",
"49-LOL",
"48-LOL",
"50-LOL",
"4F-LOL",
"4E-LOL",
"4D-LOL",
"nsLdhName=ns1.domain1.lol&cursor=ZG9tYWluNC5sb2w%3D",
"rdap_domains_four_truncated.json");
verifyMetrics(
@ -1727,10 +1727,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "ns*.domain1.lol"))
.isEqualTo(
jsonFileBuilder()
.addDomain("domain1.lol", "8A-LOL")
.addDomain("domain2.lol", "89-LOL")
.addDomain("domain3.lol", "88-LOL")
.addDomain("domain4.lol", "87-LOL")
.addDomain("domain1.lol", "8F-LOL")
.addDomain("domain2.lol", "8E-LOL")
.addDomain("domain3.lol", "8D-LOL")
.addDomain("domain4.lol", "8C-LOL")
.load("rdap_nontruncated_domains.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(SearchType.BY_NAMESERVER_NAME, Optional.of(4L), Optional.of(36L));
@ -1743,8 +1743,8 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
assertThat(generateActualJson(RequestType.NS_LDH_NAME, "ns*.domain1.lol"))
.isEqualTo(
jsonFileBuilder()
.addDomain("domain1.lol", "92-LOL")
.addDomain("domain2.lol", "91-LOL")
.addDomain("domain1.lol", "97-LOL")
.addDomain("domain2.lol", "96-LOL")
.load("rdap_incomplete_domains.json"));
assertThat(response.getStatus()).isEqualTo(200);
verifyMetrics(
@ -1909,10 +1909,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NS_IP,
"5.5.5.1",
"46-LOL",
"45-LOL",
"44-LOL",
"43-LOL",
"4B-LOL",
"4A-LOL",
"49-LOL",
"48-LOL",
"rdap_nontruncated_domains.json");
verifyMetrics(SearchType.BY_NAMESERVER_ADDRESS, 4, 1);
}
@ -1923,10 +1923,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NS_IP,
"5.5.5.1",
"47-LOL",
"46-LOL",
"45-LOL",
"44-LOL",
"4C-LOL",
"4B-LOL",
"4A-LOL",
"49-LOL",
"nsIp=5.5.5.1&cursor=ZG9tYWluNC5sb2w%3D",
"rdap_domains_four_truncated.json");
verifyMetrics(
@ -1942,10 +1942,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
runSuccessfulTestWithFourDomains(
RequestType.NS_IP,
"5.5.5.1",
"4B-LOL",
"4A-LOL",
"49-LOL",
"48-LOL",
"50-LOL",
"4F-LOL",
"4E-LOL",
"4D-LOL",
"nsIp=5.5.5.1&cursor=ZG9tYWluNC5sb2w%3D",
"rdap_domains_four_truncated.json");
verifyMetrics(

View file

@ -36,6 +36,7 @@ import google.registry.model.contact.PostalInfo;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DelegationSignerData;
@ -67,8 +68,8 @@ final class RdeFixtures {
.build();
HistoryEntry historyEntry =
persistResource(
new HistoryEntry.Builder()
.setParent(domain)
new DomainHistory.Builder()
.setDomain(domain)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(clock.nowUtc())
.setClientId("TheRegistrar")

View file

@ -71,6 +71,7 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DesignatedContact.Type;
@ -540,9 +541,9 @@ public class DatabaseHelper {
ContactResource contact, DateTime requestTime, DateTime expirationTime, DateTime now) {
HistoryEntry historyEntryContactTransfer =
persistResource(
new HistoryEntry.Builder()
new ContactHistory.Builder()
.setType(HistoryEntry.Type.CONTACT_TRANSFER_REQUEST)
.setParent(persistResource(contact))
.setContact(persistResource(contact))
.setModificationTime(now)
.setClientId(contact.getCurrentSponsorClientId())
.build()
@ -1085,8 +1086,7 @@ public class DatabaseHelper {
() -> {
tm().put(resource);
tm().put(
new HistoryEntry.Builder()
.setParent(resource)
HistoryEntry.createBuilderForResource(resource)
.setClientId(resource.getCreationClientId())
.setType(getHistoryEntryType(resource))
.setModificationTime(tm().getTransactionTime())
@ -1158,10 +1158,9 @@ public class DatabaseHelper {
public static <T extends EppResource> HistoryEntry createHistoryEntryForEppResource(
T parentResource) {
return persistResource(
new HistoryEntry.Builder()
HistoryEntry.createBuilderForResource(parentResource)
.setType(getHistoryEntryType(parentResource))
.setModificationTime(DateTime.now(DateTimeZone.UTC))
.setParent(parentResource)
.setClientId(parentResource.getPersistedCurrentSponsorClientId())
.build());
}

View file

@ -385,18 +385,16 @@ public final class FullFieldsTestEntityHelper {
Period period,
String reason,
DateTime modificationTime) {
HistoryEntry.Builder builder =
new HistoryEntry.Builder()
.setParent(resource)
.setType(type)
.setPeriod(period)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(modificationTime)
.setClientId(resource.getPersistedCurrentSponsorClientId())
.setTrid(Trid.create("ABC-123", "server-trid"))
.setBySuperuser(false)
.setReason(reason)
.setRequestedByRegistrar(false);
return builder.build();
return HistoryEntry.createBuilderForResource(resource)
.setType(type)
.setPeriod(period)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(modificationTime)
.setClientId(resource.getPersistedCurrentSponsorClientId())
.setTrid(Trid.create("ABC-123", "server-trid"))
.setBySuperuser(false)
.setReason(reason)
.setRequestedByRegistrar(false)
.build();
}
}

View file

@ -128,8 +128,7 @@ class DedupeOneTimeBillingEventIdsCommandTest
private HistoryEntry persistHistoryEntry(EppResource parent) {
return persistResource(
new HistoryEntry.Builder()
.setParent(parent)
HistoryEntry.createBuilderForResource(parent)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(Period.create(1, Period.Unit.YEARS))
.setXmlBytes("<xml></xml>".getBytes(UTF_8))

View file

@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.truth.Truth8;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.registrar.Registrar;
import google.registry.model.reporting.HistoryEntry;
import google.registry.schema.domain.RegistryLock;
@ -127,11 +128,11 @@ class BackfillRegistryLocksCommandTest extends CommandTestCase<BackfillRegistryL
DateTime ursTime = fakeClock.nowUtc();
DomainBase ursDomain = persistLockedDomain("urs.tld");
HistoryEntry historyEntry =
new HistoryEntry.Builder()
new DomainHistory.Builder()
.setBySuperuser(true)
.setClientId("adminreg")
.setModificationTime(ursTime)
.setParent(ursDomain)
.setDomain(ursDomain)
.setReason("Uniform Rapid Suspension")
.setType(HistoryEntry.Type.DOMAIN_UPDATE)
.setRequestedByRegistrar(false)

View file

@ -106,8 +106,7 @@ class KillAllEppResourcesActionTest extends MapreduceTestCase<KillAllEppResource
persistActiveHost("ns.foo.tld1"),
persistActiveHost("ns.foo.tld2"))) {
HistoryEntry history =
new HistoryEntry.Builder()
.setParent(resource)
HistoryEntry.createBuilderForResource(resource)
.setClientId(resource.getCreationClientId())
.setModificationTime(resource.getCreationTime())
.setType(HISTORY_ENTRY_CREATE_TYPES.get(resource.getClass()))

View file

@ -23,8 +23,10 @@ import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.reporting.HistoryEntry;
import google.registry.testing.FakeResponse;
import google.registry.testing.mapreduce.MapreduceTestCase;
@ -58,22 +60,24 @@ class ResaveAllHistoryEntriesActionTest extends MapreduceTestCase<ResaveAllHisto
auditedOfy()
.save()
.toEntity(
new HistoryEntry.Builder()
.setParent(domain)
new DomainHistory.Builder()
.setDomain(domain)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(domain.getCreationTime())
.setClientId(domain.getCreationClientId())
.build());
.build()
.asHistoryEntry());
Entity contactEntry =
auditedOfy()
.save()
.toEntity(
new HistoryEntry.Builder()
.setParent(contact)
new ContactHistory.Builder()
.setContact(contact)
.setType(HistoryEntry.Type.CONTACT_CREATE)
.setClientId(contact.getCreationClientId())
.setModificationTime(contact.getCreationTime())
.build());
.build()
.asHistoryEntry());
// Set raw properties outside the Objectify schema, which will be deleted upon re-save.
domainEntry.setProperty("clientId", "validId");

View file

@ -287,7 +287,10 @@ class google.registry.model.domain.DomainHistory {
java.lang.String clientId;
java.lang.String otherClientId;
java.lang.String reason;
java.util.Set<google.registry.model.domain.GracePeriod$GracePeriodHistory> gracePeriodHistories;
java.util.Set<google.registry.model.domain.secdns.DomainDsDataHistory> dsDataHistories;
java.util.Set<google.registry.model.reporting.DomainTransactionRecord> domainTransactionRecords;
java.util.Set<google.registry.persistence.VKey<google.registry.model.host.HostResource>> nsHosts;
org.joda.time.DateTime modificationTime;
}
class google.registry.model.domain.GracePeriod {
@ -298,6 +301,16 @@ class google.registry.model.domain.GracePeriod {
long gracePeriodId;
org.joda.time.DateTime expirationTime;
}
class google.registry.model.domain.GracePeriod$GracePeriodHistory {
google.registry.model.domain.rgp.GracePeriodStatus type;
google.registry.persistence.BillingVKey$BillingEventVKey billingEventOneTime;
google.registry.persistence.BillingVKey$BillingRecurrenceVKey billingEventRecurring;
java.lang.Long domainHistoryRevisionId;
java.lang.Long gracePeriodHistoryRevisionId;
java.lang.String clientId;
long gracePeriodId;
org.joda.time.DateTime expirationTime;
}
class google.registry.model.domain.Period {
google.registry.model.domain.Period$Unit unit;
java.lang.Integer value;
@ -330,6 +343,14 @@ class google.registry.model.domain.secdns.DelegationSignerData {
int digestType;
int keyTag;
}
class google.registry.model.domain.secdns.DomainDsDataHistory {
byte[] digest;
int algorithm;
int digestType;
int keyTag;
java.lang.Long domainHistoryRevisionId;
java.lang.Long dsDataHistoryRevisionId;
}
class google.registry.model.domain.token.AllocationToken {
@Id java.lang.String token;
boolean discountPremiums;