Persist *History objects as HistoryEntry objects (#749)

* Persist *History objects as HistoryEntry objects

While Datastore is the primary database, we will store *History objects
as HistoryEntry objects and convert to/from the proper objects in the
Datastore transaction manager. This means that History objects will not
properly store the copy of the EppResource until we move to SQL as
primary, but this is the way the world exists anyway so it's not a
problem.

* Format code and simplify the bulk loading

* Add comments with context
This commit is contained in:
gbrodman 2020-08-26 11:45:09 -04:00 committed by GitHub
parent df15b38a1e
commit 266bd43792
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 401 additions and 54 deletions

View file

@ -19,9 +19,12 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.common.Cursor;
import google.registry.model.common.EntityGroupRoot;
import google.registry.model.common.GaeUserIdConverter;
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.domain.token.AllocationToken;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostResource;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.EppResourceIndexBucket;
@ -68,9 +71,11 @@ public final class EntityClasses {
CommitLogCheckpointRoot.class,
CommitLogManifest.class,
CommitLogMutation.class,
ContactHistory.class,
ContactResource.class,
Cursor.class,
DomainBase.class,
DomainHistory.class,
EntityGroupRoot.class,
EppResourceIndex.class,
EppResourceIndexBucket.class,
@ -79,6 +84,7 @@ public final class EntityClasses {
ForeignKeyIndex.ForeignKeyHostIndex.class,
GaeUserIdConverter.class,
HistoryEntry.class,
HostHistory.class,
HostResource.class,
KmsSecret.class,
KmsSecretRevision.class,

View file

@ -15,6 +15,7 @@
package google.registry.model.contact;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.EntitySubclass;
import google.registry.model.EppResource;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
@ -36,6 +37,7 @@ import javax.persistence.Entity;
@javax.persistence.Index(columnList = "historyType"),
@javax.persistence.Index(columnList = "historyModificationTime")
})
@EntitySubclass
public class ContactHistory extends HistoryEntry {
// Store ContactBase instead of ContactResource so we don't pick up its @Id
ContactBase contactBase;

View file

@ -15,6 +15,7 @@
package google.registry.model.domain;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.EntitySubclass;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactResource;
import google.registry.model.host.HostResource;
@ -43,6 +44,7 @@ import javax.persistence.JoinTable;
@javax.persistence.Index(columnList = "historyType"),
@javax.persistence.Index(columnList = "historyModificationTime")
})
@EntitySubclass
public class DomainHistory extends HistoryEntry {
// Store DomainContent instead of DomainBase so we don't pick up its @Id
DomainContent domainContent;

View file

@ -15,6 +15,7 @@
package google.registry.model.host;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.EntitySubclass;
import google.registry.model.EppResource;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
@ -37,6 +38,7 @@ import javax.persistence.Entity;
@javax.persistence.Index(columnList = "historyType"),
@javax.persistence.Index(columnList = "historyModificationTime")
})
@EntitySubclass
public class HostHistory extends HistoryEntry {
// Store HostBase instead of HostResource so we don't pick up its @Id

View file

@ -24,13 +24,16 @@ import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.Key;
import google.registry.model.contact.ContactHistory;
import google.registry.model.host.HostHistory;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.TransactionManager;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.StreamSupport;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
/** Datastore implementation of {@link TransactionManager}. */
@ -99,8 +102,7 @@ public class DatastoreTransactionManager implements TransactionManager {
@Override
public void saveNew(Object entity) {
checkArgumentNotNull(entity, "entity must be specified");
getOfy().save().entity(entity);
saveEntity(entity);
}
@Override
@ -110,8 +112,7 @@ public class DatastoreTransactionManager implements TransactionManager {
@Override
public void saveNewOrUpdate(Object entity) {
checkArgumentNotNull(entity, "entity must be specified");
getOfy().save().entity(entity);
saveEntity(entity);
}
@Override
@ -121,8 +122,7 @@ public class DatastoreTransactionManager implements TransactionManager {
@Override
public void update(Object entity) {
checkArgumentNotNull(entity, "entity must be specified");
getOfy().save().entity(entity);
saveEntity(entity);
}
@Override
@ -137,7 +137,7 @@ public class DatastoreTransactionManager implements TransactionManager {
@Override
public <T> boolean checkExists(VKey<T> key) {
return getOfy().load().key(key.getOfyKey()).now() != null;
return loadNullable(key) != null;
}
// TODO: add tests for these methods. They currently have some degree of test coverage because
@ -146,12 +146,12 @@ public class DatastoreTransactionManager implements TransactionManager {
// interface tests that are applied to both the datastore and SQL implementations.
@Override
public <T> Optional<T> maybeLoad(VKey<T> key) {
return Optional.ofNullable(getOfy().load().key(key.getOfyKey()).now());
return Optional.ofNullable(loadNullable(key));
}
@Override
public <T> T load(VKey<T> key) {
T result = getOfy().load().key(key.getOfyKey()).now();
T result = loadNullable(key);
if (result == null) {
throw new NoSuchElementException(key.toString());
}
@ -167,7 +167,10 @@ public class DatastoreTransactionManager implements TransactionManager {
.collect(toImmutableMap(key -> (Key<T>) key.getOfyKey(), Functions.identity()));
return getOfy().load().keys(keyMap.keySet()).entrySet().stream()
.collect(ImmutableMap.toImmutableMap(entry -> keyMap.get(entry.getKey()), Entry::getValue));
.collect(
toImmutableMap(
entry -> keyMap.get(entry.getKey()),
entry -> toChildHistoryEntryIfPossible(entry.getValue())));
}
@Override
@ -191,4 +194,37 @@ public class DatastoreTransactionManager implements TransactionManager {
.collect(toImmutableList());
getOfy().delete().keys(list).now();
}
/**
* The following three methods exist due to the migration to Cloud SQL.
*
* <p>In Cloud SQL, {@link HistoryEntry} objects are represented instead as {@link DomainHistory},
* {@link ContactHistory}, and {@link HostHistory} objects. During the migration, we do not wish
* to change the Datastore schema so all of these objects are stored in Datastore as HistoryEntry
* objects. They are converted to/from the appropriate classes upon retrieval, and converted to
* HistoryEntry on save. See go/r3.0-history-objects for more details.
*/
private void saveEntity(Object entity) {
checkArgumentNotNull(entity, "entity must be specified");
if (entity instanceof HistoryEntry) {
entity = ((HistoryEntry) entity).asHistoryEntry();
}
getOfy().save().entity(entity);
}
@SuppressWarnings("unchecked")
private <T> T toChildHistoryEntryIfPossible(@Nullable T obj) {
// NB: The Key of the object in question may not necessarily be the resulting class that we
// wish to have. Because all *History classes are @EntitySubclasses, their Keys will have type
// HistoryEntry -- even if you create them based off the *History class.
if (obj != null && HistoryEntry.class.isAssignableFrom(obj.getClass())) {
return (T) ((HistoryEntry) obj).toChildHistoryEntity();
}
return obj;
}
@Nullable
private <T> T loadNullable(VKey<T> key) {
return toChildHistoryEntryIfPossible(getOfy().load().key(key.getOfyKey()).now());
}
}

View file

@ -14,8 +14,10 @@
package google.registry.model.reporting;
import static com.googlecode.objectify.Key.getKind;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
@ -28,8 +30,14 @@ 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.ContactHistory;
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.host.HostHistory;
import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
import java.util.Set;
@ -111,7 +119,8 @@ public class HistoryEntry extends ImmutableObject implements Buildable {
@Id
@javax.persistence.Id
@Column(name = "historyRevisionId")
Long id;
@VisibleForTesting
public Long id;
/** The resource this event mutated. */
@Parent @Transient protected Key<? extends EppResource> parent;
@ -259,6 +268,39 @@ public class HistoryEntry extends ImmutableObject implements Buildable {
return new Builder(clone(this));
}
public HistoryEntry asHistoryEntry() {
return new Builder().copyFrom(this).build();
}
public HistoryEntry toChildHistoryEntity() {
String parentKind = getParent().getKind();
final HistoryEntry resultEntity;
// can't use a switch statement since we're calling getKind()
if (parentKind.equals(getKind(DomainBase.class))) {
resultEntity =
new DomainHistory.Builder()
.copyFrom(this)
.setDomainRepoId(VKey.create(DomainBase.class, parent.getName(), parent))
.build();
} else if (parentKind.equals(getKind(HostResource.class))) {
resultEntity =
new HostHistory.Builder()
.copyFrom(this)
.setHostRepoId(VKey.create(HostResource.class, parent.getName(), parent))
.build();
} else if (parentKind.equals(getKind(ContactResource.class))) {
resultEntity =
new ContactHistory.Builder()
.copyFrom(this)
.setContactRepoId(VKey.create(ContactResource.class, parent.getName(), parent))
.build();
} else {
throw new IllegalStateException(
String.format("Unknown kind of HistoryEntry parent %s", parentKind));
}
return resultEntity;
}
/** A builder for {@link HistoryEntry} since it is immutable */
public static class Builder<T extends HistoryEntry, B extends Builder<?, ?>>
extends GenericBuilder<T, B> {
@ -268,17 +310,40 @@ public class HistoryEntry extends ImmutableObject implements Buildable {
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(nullToEmptyImmutableCopy(historyEntry.domainTransactionRecords));
return thisCastToDerived();
}
@Override
public T build() {
return super.build();
}
public B setId(long id) {
getInstance().id = id;
return thisCastToDerived();
}
public 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) {
getInstance().parent = parent;
return thisCastToDerived();

View file

@ -17,11 +17,14 @@ package google.registry.model.history;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatastoreHelper.newContactResourceWithRoid;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.googlecode.objectify.Key;
import google.registry.model.EntityTestCase;
import google.registry.model.contact.ContactBase;
import google.registry.model.contact.ContactHistory;
import google.registry.model.contact.ContactResource;
import google.registry.model.eppcommon.Trid;
@ -44,19 +47,8 @@ public class ContactHistoryTest extends EntityTestCase {
jpaTm().transact(() -> jpaTm().saveNew(contact));
VKey<ContactResource> contactVKey = contact.createVKey();
ContactResource contactFromDb = jpaTm().transact(() -> jpaTm().load(contactVKey));
ContactHistory contactHistory =
new ContactHistory.Builder()
.setType(HistoryEntry.Type.HOST_CREATE)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(fakeClock.nowUtc())
.setClientId("TheRegistrar")
.setTrid(Trid.create("ABC-123", "server-trid"))
.setBySuperuser(false)
.setReason("reason")
.setRequestedByRegistrar(true)
.setContactBase(contactFromDb)
.setContactRepoId(contactVKey)
.build();
ContactHistory contactHistory = createContactHistory(contactFromDb, contactVKey);
contactHistory.id = null;
jpaTm().transact(() -> jpaTm().saveNew(contactHistory));
jpaTm()
.transact(
@ -68,6 +60,47 @@ public class ContactHistoryTest extends EntityTestCase {
});
}
@Test
void testOfyPersistence() {
saveRegistrar("TheRegistrar");
ContactResource contact = newContactResourceWithRoid("contactId", "contact1");
tm().transact(() -> tm().saveNew(contact));
VKey<ContactResource> contactVKey = contact.createVKey();
ContactResource contactFromDb = tm().transact(() -> tm().load(contactVKey));
fakeClock.advanceOneMilli();
ContactHistory contactHistory = createContactHistory(contactFromDb, contactVKey);
tm().transact(() -> tm().saveNew(contactHistory));
// retrieving a HistoryEntry or a ContactHistory with the same key should return the same object
// note: due to the @EntitySubclass annotation. all Keys for ContactHistory objects will have
// type HistoryEntry
VKey<ContactHistory> contactHistoryVKey =
VKey.createOfy(ContactHistory.class, Key.create(contactHistory));
VKey<HistoryEntry> historyEntryVKey =
VKey.createOfy(HistoryEntry.class, Key.create(contactHistory.asHistoryEntry()));
ContactHistory hostHistoryFromDb = tm().transact(() -> tm().load(contactHistoryVKey));
HistoryEntry historyEntryFromDb = tm().transact(() -> tm().load(historyEntryVKey));
assertThat(hostHistoryFromDb).isEqualTo(historyEntryFromDb);
}
private ContactHistory createContactHistory(
ContactBase contact, VKey<ContactResource> contactVKey) {
return new ContactHistory.Builder()
.setType(HistoryEntry.Type.HOST_CREATE)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(fakeClock.nowUtc())
.setClientId("TheRegistrar")
.setTrid(Trid.create("ABC-123", "server-trid"))
.setBySuperuser(false)
.setReason("reason")
.setRequestedByRegistrar(true)
.setContactBase(contact)
.setContactRepoId(contactVKey)
.build();
}
static void assertContactHistoriesEqual(ContactHistory one, ContactHistory two) {
assertAboutImmutableObjects()
.that(one)

View file

@ -17,15 +17,18 @@ package google.registry.model.history;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatastoreHelper.newContactResourceWithRoid;
import static google.registry.testing.DatastoreHelper.newDomainBase;
import static google.registry.testing.DatastoreHelper.newHostResourceWithRoid;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.googlecode.objectify.Key;
import google.registry.model.EntityTestCase;
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.eppcommon.Trid;
import google.registry.model.host.HostResource;
@ -45,9 +48,14 @@ public class DomainHistoryTest extends EntityTestCase {
saveRegistrar("TheRegistrar");
HostResource host = newHostResourceWithRoid("ns1.example.com", "host1");
jpaTm().transact(() -> jpaTm().saveNew(host));
ContactResource contact = newContactResourceWithRoid("contactId", "contact1");
jpaTm().transact(() -> jpaTm().saveNew(contact));
jpaTm()
.transact(
() -> {
jpaTm().saveNew(host);
jpaTm().saveNew(contact);
});
DomainBase domain =
newDomainBase("example.tld", "domainRepoId", contact)
@ -56,19 +64,8 @@ public class DomainHistoryTest extends EntityTestCase {
.build();
jpaTm().transact(() -> jpaTm().saveNew(domain));
DomainHistory domainHistory =
new DomainHistory.Builder()
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(fakeClock.nowUtc())
.setClientId("TheRegistrar")
.setTrid(Trid.create("ABC-123", "server-trid"))
.setBySuperuser(false)
.setReason("reason")
.setRequestedByRegistrar(true)
.setDomainContent(domain)
.setDomainRepoId(domain.createVKey())
.build();
DomainHistory domainHistory = createDomainHistory(domain);
domainHistory.id = null;
jpaTm().transact(() -> jpaTm().saveNew(domainHistory));
jpaTm()
@ -82,9 +79,62 @@ public class DomainHistoryTest extends EntityTestCase {
});
}
@Test
void testOfyPersistence() {
saveRegistrar("TheRegistrar");
HostResource host = newHostResourceWithRoid("ns1.example.com", "host1");
ContactResource contact = newContactResourceWithRoid("contactId", "contact1");
tm().transact(
() -> {
tm().saveNew(host);
tm().saveNew(contact);
});
fakeClock.advanceOneMilli();
DomainBase domain =
newDomainBase("example.tld", "domainRepoId", contact)
.asBuilder()
.setNameservers(host.createVKey())
.build();
tm().transact(() -> tm().saveNew(domain));
fakeClock.advanceOneMilli();
DomainHistory domainHistory = createDomainHistory(domain);
tm().transact(() -> tm().saveNew(domainHistory));
// retrieving a HistoryEntry or a DomainHistory with the same key should return the same object
// note: due to the @EntitySubclass annotation. all Keys for ContactHistory objects will have
// type HistoryEntry
VKey<DomainHistory> domainHistoryVKey =
VKey.createOfy(DomainHistory.class, Key.create(domainHistory));
VKey<HistoryEntry> historyEntryVKey =
VKey.createOfy(HistoryEntry.class, Key.create(domainHistory.asHistoryEntry()));
DomainHistory domainHistoryFromDb = tm().transact(() -> tm().load(domainHistoryVKey));
HistoryEntry historyEntryFromDb = tm().transact(() -> tm().load(historyEntryVKey));
assertThat(domainHistoryFromDb).isEqualTo(historyEntryFromDb);
}
static void assertDomainHistoriesEqual(DomainHistory one, DomainHistory two) {
assertAboutImmutableObjects()
.that(one)
.isEqualExceptFields(two, "domainContent", "domainRepoId", "parent");
}
private DomainHistory createDomainHistory(DomainContent domain) {
return new DomainHistory.Builder()
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(fakeClock.nowUtc())
.setClientId("TheRegistrar")
.setTrid(Trid.create("ABC-123", "server-trid"))
.setBySuperuser(false)
.setReason("reason")
.setRequestedByRegistrar(true)
.setDomainContent(domain)
.setDomainRepoId(domain.createVKey())
.build();
}
}

View file

@ -17,12 +17,15 @@ package google.registry.model.history;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatastoreHelper.newHostResourceWithRoid;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.googlecode.objectify.Key;
import google.registry.model.EntityTestCase;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostBase;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostResource;
import google.registry.model.reporting.HistoryEntry;
@ -44,19 +47,8 @@ public class HostHistoryTest extends EntityTestCase {
jpaTm().transact(() -> jpaTm().saveNew(host));
VKey<HostResource> hostVKey = VKey.createSql(HostResource.class, "host1");
HostResource hostFromDb = jpaTm().transact(() -> jpaTm().load(hostVKey));
HostHistory hostHistory =
new HostHistory.Builder()
.setType(HistoryEntry.Type.HOST_CREATE)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(fakeClock.nowUtc())
.setClientId("TheRegistrar")
.setTrid(Trid.create("ABC-123", "server-trid"))
.setBySuperuser(false)
.setReason("reason")
.setRequestedByRegistrar(true)
.setHostBase(hostFromDb)
.setHostRepoId(hostVKey)
.build();
HostHistory hostHistory = createHostHistory(hostFromDb, hostVKey);
hostHistory.id = null;
jpaTm().transact(() -> jpaTm().saveNew(hostHistory));
jpaTm()
.transact(
@ -69,10 +61,49 @@ public class HostHistoryTest extends EntityTestCase {
});
}
@Test
public void testOfySave() {
saveRegistrar("registrar1");
HostResource host = newHostResourceWithRoid("ns1.example.com", "host1");
tm().transact(() -> tm().saveNew(host));
VKey<HostResource> hostVKey = VKey.create(HostResource.class, "host1", Key.create(host));
HostResource hostFromDb = tm().transact(() -> tm().load(hostVKey));
HostHistory hostHistory = createHostHistory(hostFromDb, hostVKey);
fakeClock.advanceOneMilli();
tm().transact(() -> tm().saveNew(hostHistory));
// retrieving a HistoryEntry or a HostHistory with the same key should return the same object
// note: due to the @EntitySubclass annotation. all Keys for ContactHistory objects will have
// type HistoryEntry
VKey<HostHistory> hostHistoryVKey = VKey.createOfy(HostHistory.class, Key.create(hostHistory));
VKey<HistoryEntry> historyEntryVKey =
VKey.createOfy(HistoryEntry.class, Key.create(hostHistory.asHistoryEntry()));
HostHistory hostHistoryFromDb = tm().transact(() -> tm().load(hostHistoryVKey));
HistoryEntry historyEntryFromDb = tm().transact(() -> tm().load(historyEntryVKey));
assertThat(hostHistoryFromDb).isEqualTo(historyEntryFromDb);
}
private void assertHostHistoriesEqual(HostHistory one, HostHistory two) {
assertAboutImmutableObjects().that(one).isEqualExceptFields(two, "hostBase");
assertAboutImmutableObjects()
.that(one.getHostBase())
.isEqualExceptFields(two.getHostBase(), "repoId");
}
private HostHistory createHostHistory(HostBase hostBase, VKey<HostResource> hostVKey) {
return new HostHistory.Builder()
.setType(HistoryEntry.Type.HOST_CREATE)
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
.setModificationTime(fakeClock.nowUtc())
.setClientId("TheRegistrar")
.setTrid(Trid.create("ABC-123", "server-trid"))
.setBySuperuser(false)
.setReason("reason")
.setRequestedByRegistrar(true)
.setHostBase(hostBase)
.setHostRepoId(hostVKey)
.build();
}
}

View file

@ -99,6 +99,46 @@ class google.registry.model.contact.ContactAddress {
class google.registry.model.contact.ContactAuthInfo {
google.registry.model.eppcommon.AuthInfo$PasswordAuth pw;
}
class google.registry.model.contact.ContactBase {
@Id java.lang.String repoId;
com.google.common.collect.ImmutableSortedMap<org.joda.time.DateTime, com.googlecode.objectify.Key<google.registry.model.ofy.CommitLogManifest>> revisions;
google.registry.model.CreateAutoTimestamp creationTime;
google.registry.model.UpdateAutoTimestamp updateTimestamp;
google.registry.model.contact.ContactAuthInfo authInfo;
google.registry.model.contact.ContactPhoneNumber fax;
google.registry.model.contact.ContactPhoneNumber voice;
google.registry.model.contact.Disclose disclose;
google.registry.model.contact.PostalInfo internationalizedPostalInfo;
google.registry.model.contact.PostalInfo localizedPostalInfo;
google.registry.model.transfer.ContactTransferData transferData;
java.lang.String contactId;
java.lang.String creationClientId;
java.lang.String currentSponsorClientId;
java.lang.String email;
java.lang.String lastEppUpdateClientId;
java.lang.String searchName;
java.util.Set<google.registry.model.eppcommon.StatusValue> status;
org.joda.time.DateTime deletionTime;
org.joda.time.DateTime lastEppUpdateTime;
org.joda.time.DateTime lastTransferTime;
}
class google.registry.model.contact.ContactHistory {
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<? extends google.registry.model.EppResource> parent;
boolean bySuperuser;
byte[] xmlBytes;
google.registry.model.contact.ContactBase contactBase;
google.registry.model.domain.Period period;
google.registry.model.eppcommon.Trid trid;
google.registry.model.reporting.HistoryEntry$Type type;
google.registry.persistence.VKey<google.registry.model.contact.ContactResource> contactRepoId;
java.lang.Boolean requestedByRegistrar;
java.lang.String clientId;
java.lang.String otherClientId;
java.lang.String reason;
java.util.Set<google.registry.model.reporting.DomainTransactionRecord> domainTransactionRecords;
org.joda.time.DateTime modificationTime;
}
class google.registry.model.contact.ContactPhoneNumber {
java.lang.String extension;
java.lang.String phoneNumber;
@ -191,6 +231,52 @@ class google.registry.model.domain.DomainBase {
org.joda.time.DateTime lastTransferTime;
org.joda.time.DateTime registrationExpirationTime;
}
class google.registry.model.domain.DomainContent {
@Id java.lang.String repoId;
com.google.common.collect.ImmutableSortedMap<org.joda.time.DateTime, com.googlecode.objectify.Key<google.registry.model.ofy.CommitLogManifest>> revisions;
google.registry.model.CreateAutoTimestamp creationTime;
google.registry.model.UpdateAutoTimestamp updateTimestamp;
google.registry.model.domain.DomainAuthInfo authInfo;
google.registry.model.domain.launch.LaunchNotice launchNotice;
google.registry.model.transfer.DomainTransferData transferData;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> autorenewBillingEvent;
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$Autorenew> autorenewPollMessage;
google.registry.persistence.VKey<google.registry.model.poll.PollMessage$OneTime> deletePollMessage;
java.lang.String creationClientId;
java.lang.String currentSponsorClientId;
java.lang.String fullyQualifiedDomainName;
java.lang.String idnTableName;
java.lang.String lastEppUpdateClientId;
java.lang.String smdId;
java.lang.String tld;
java.util.Set<google.registry.model.domain.DesignatedContact> allContacts;
java.util.Set<google.registry.model.domain.GracePeriod> gracePeriods;
java.util.Set<google.registry.model.domain.secdns.DelegationSignerData> dsData;
java.util.Set<google.registry.model.eppcommon.StatusValue> status;
java.util.Set<google.registry.persistence.VKey<google.registry.model.host.HostResource>> nsHosts;
java.util.Set<java.lang.String> subordinateHosts;
org.joda.time.DateTime deletionTime;
org.joda.time.DateTime lastEppUpdateTime;
org.joda.time.DateTime lastTransferTime;
org.joda.time.DateTime registrationExpirationTime;
}
class google.registry.model.domain.DomainHistory {
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<? extends google.registry.model.EppResource> parent;
boolean bySuperuser;
byte[] xmlBytes;
google.registry.model.domain.DomainContent domainContent;
google.registry.model.domain.Period period;
google.registry.model.eppcommon.Trid trid;
google.registry.model.reporting.HistoryEntry$Type type;
google.registry.persistence.VKey<google.registry.model.domain.DomainBase> domainRepoId;
java.lang.Boolean requestedByRegistrar;
java.lang.String clientId;
java.lang.String otherClientId;
java.lang.String reason;
java.util.Set<google.registry.model.reporting.DomainTransactionRecord> domainTransactionRecords;
org.joda.time.DateTime modificationTime;
}
class google.registry.model.domain.GracePeriod {
google.registry.model.domain.rgp.GracePeriodStatus type;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$OneTime> billingEventOneTime;
@ -288,6 +374,40 @@ class google.registry.model.eppcommon.Trid {
java.lang.String clientTransactionId;
java.lang.String serverTransactionId;
}
class google.registry.model.host.HostBase {
@Id java.lang.String repoId;
com.google.common.collect.ImmutableSortedMap<org.joda.time.DateTime, com.googlecode.objectify.Key<google.registry.model.ofy.CommitLogManifest>> revisions;
google.registry.model.CreateAutoTimestamp creationTime;
google.registry.model.UpdateAutoTimestamp updateTimestamp;
google.registry.persistence.VKey<google.registry.model.domain.DomainBase> superordinateDomain;
java.lang.String creationClientId;
java.lang.String currentSponsorClientId;
java.lang.String fullyQualifiedHostName;
java.lang.String lastEppUpdateClientId;
java.util.Set<google.registry.model.eppcommon.StatusValue> status;
java.util.Set<java.net.InetAddress> inetAddresses;
org.joda.time.DateTime deletionTime;
org.joda.time.DateTime lastEppUpdateTime;
org.joda.time.DateTime lastSuperordinateChange;
org.joda.time.DateTime lastTransferTime;
}
class google.registry.model.host.HostHistory {
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<? extends google.registry.model.EppResource> parent;
boolean bySuperuser;
byte[] xmlBytes;
google.registry.model.domain.Period period;
google.registry.model.eppcommon.Trid trid;
google.registry.model.host.HostBase hostBase;
google.registry.model.reporting.HistoryEntry$Type type;
google.registry.persistence.VKey<google.registry.model.host.HostResource> hostRepoId;
java.lang.Boolean requestedByRegistrar;
java.lang.String clientId;
java.lang.String otherClientId;
java.lang.String reason;
java.util.Set<google.registry.model.reporting.DomainTransactionRecord> domainTransactionRecords;
org.joda.time.DateTime modificationTime;
}
class google.registry.model.host.HostResource {
@Id java.lang.String repoId;
com.google.common.collect.ImmutableSortedMap<org.joda.time.DateTime, com.googlecode.objectify.Key<google.registry.model.ofy.CommitLogManifest>> revisions;