Begin saving the EppResource parent in *History objects (#1090)

* Begin saving the EppResource parent in *History objects

We use DomainCreateFlow as an example here of how this will work. There
were a few changes necessary:

- various changes around GracePeriod / GracePeriodHistory so that we can
actually store them without throwing NPEs
- Creating one injectable *History.Builder field and using in place of
the HistoryEntry.Builder injected field in DomainCreateFlow
- Saving the EppResource as the parent in the *History.Builder setParent
calls
- Converting to/from HistoryEntry/*History classes in
DatastoreTransactionManager. Basically, we'll want to return the
*History subclasses (and similar in the ofy portions of HistoryEntryDao)
- Converting a few HistoryEntry.Builder usages to DomainHistory.Builder
usages. Eventually we should convert all of them.
This commit is contained in:
gbrodman 2021-04-22 15:03:37 -04:00 committed by GitHub
parent 40db04db8d
commit 9f69a0bf2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 202 additions and 135 deletions

View file

@ -751,11 +751,11 @@ class EppLifecycleDomainTest extends EppTestCase {
.hasResponse(
"poll_response_autorenew.xml",
ImmutableMap.of(
"ID", "1-C-EXAMPLE-13-16-2002",
"ID", "1-D-EXAMPLE-11-16-2002",
"QDATE", "2002-06-01T00:04:00Z",
"DOMAIN", "fakesite.example",
"EXDATE", "2003-06-01T00:04:00Z"));
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-13-16-2002"))
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-D-EXAMPLE-11-16-2002"))
.atTime("2002-07-01T00:02:00Z")
.hasResponse("poll_ack_response_empty.xml");
@ -769,13 +769,13 @@ class EppLifecycleDomainTest extends EppTestCase {
.hasResponse(
"poll_response_autorenew.xml",
ImmutableMap.of(
"ID", "1-C-EXAMPLE-13-16-2003", // Note -- Year is different from previous ID.
"ID", "1-D-EXAMPLE-11-16-2003", // Note -- Year is different from previous ID.
"QDATE", "2003-06-01T00:04:00Z",
"DOMAIN", "fakesite.example",
"EXDATE", "2004-06-01T00:04:00Z"));
// Ack the second poll message and verify that none remain.
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-C-EXAMPLE-13-16-2003"))
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-D-EXAMPLE-11-16-2003"))
.atTime("2003-07-01T00:05:05Z")
.hasResponse("poll_ack_response_empty.xml");
assertThatCommand("poll.xml")
@ -805,7 +805,7 @@ class EppLifecycleDomainTest extends EppTestCase {
// As the losing registrar, read the request poll message, and then ack it.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
String messageId = "1-C-EXAMPLE-18-24-2001";
String messageId = "1-D-EXAMPLE-19-25-2001";
assertThatCommand("poll.xml")
.atTime("2001-01-01T00:01:00Z")
.hasResponse("poll_response_domain_transfer_request.xml", ImmutableMap.of("ID", messageId));
@ -814,7 +814,7 @@ class EppLifecycleDomainTest extends EppTestCase {
.hasResponse("poll_ack_response_empty.xml");
// Five days in the future, expect a server approval poll message to the loser, and ack it.
messageId = "1-C-EXAMPLE-18-23-2001";
messageId = "1-D-EXAMPLE-19-24-2001";
assertThatCommand("poll.xml")
.atTime("2001-01-06T00:01:00Z")
.hasResponse(
@ -826,7 +826,7 @@ class EppLifecycleDomainTest extends EppTestCase {
assertThatLogoutSucceeds();
// Also expect a server approval poll message to the winner, with the transfer request trid.
messageId = "1-C-EXAMPLE-18-22-2001";
messageId = "1-D-EXAMPLE-19-23-2001";
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("poll.xml")
.atTime("2001-01-06T00:02:00Z")

View file

@ -403,7 +403,7 @@ class DomainTransferCancelFlowTest
persistResource(
new DomainHistory.Builder()
.setType(DOMAIN_TRANSFER_REQUEST)
.setParent(domain)
.setDomainContent(domain)
.setModificationTime(clock.nowUtc().minusDays(4))
.setDomainTransactionRecords(
ImmutableSet.of(previousSuccessRecord, notCancellableRecord))

View file

@ -35,8 +35,10 @@ import google.registry.model.EppResource;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Reason;
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.index.EppResourceIndex;
import google.registry.model.reporting.HistoryEntry;
import google.registry.testing.AppEngineExtension;
@ -64,9 +66,9 @@ class ChildEntityInputTest {
private DomainBase domainA;
private DomainBase domainB;
private HistoryEntry domainHistoryEntryA;
private HistoryEntry domainHistoryEntryB;
private HistoryEntry contactHistoryEntry;
private DomainHistory domainHistoryEntryA;
private DomainHistory domainHistoryEntryB;
private ContactHistory contactHistoryEntry;
private BillingEvent.OneTime oneTimeA;
private BillingEvent.OneTime oneTimeB;
private BillingEvent.Recurring recurringA;
@ -78,10 +80,10 @@ class ChildEntityInputTest {
domainA = persistEppResourceInFirstBucket(newDomainBase("a.tld", contact));
domainHistoryEntryA =
persistResource(
new HistoryEntry.Builder().setParent(domainA).setModificationTime(now).build());
new DomainHistory.Builder().setDomainContent(domainA).setModificationTime(now).build());
contactHistoryEntry =
persistResource(
new HistoryEntry.Builder().setParent(contact).setModificationTime(now).build());
new ContactHistory.Builder().setContactBase(contact).setModificationTime(now).build());
oneTimeA =
persistResource(
new BillingEvent.OneTime.Builder()
@ -111,7 +113,7 @@ class ChildEntityInputTest {
domainB = persistEppResourceInFirstBucket(newDomainBase("b.tld"));
domainHistoryEntryB =
persistResource(
new HistoryEntry.Builder().setParent(domainB).setModificationTime(now).build());
new DomainHistory.Builder().setDomainContent(domainB).setModificationTime(now).build());
oneTimeB =
persistResource(
new BillingEvent.OneTime.Builder()
@ -177,9 +179,9 @@ class ChildEntityInputTest {
}
assertThat(seen)
.containsExactly(
domainHistoryEntryA,
domainHistoryEntryB,
contactHistoryEntry,
domainHistoryEntryA.asHistoryEntry(),
domainHistoryEntryB.asHistoryEntry(),
contactHistoryEntry.asHistoryEntry(),
oneTimeA,
recurringA,
oneTimeB,
@ -202,7 +204,11 @@ class ChildEntityInputTest {
.createReaders()
.get(0);
assertThat(getAllFromReader(reader))
.containsExactly(domainHistoryEntryA, contactHistoryEntry, oneTimeA, recurringA);
.containsExactly(
domainHistoryEntryA.asHistoryEntry(),
contactHistoryEntry.asHistoryEntry(),
oneTimeA,
recurringA);
}
private static Set<ImmutableObject> getAllFromReader(InputReader<ImmutableObject> reader)
@ -230,7 +236,7 @@ class ChildEntityInputTest {
HistoryEntry.class, BillingEvent.OneTime.class, BillingEvent.Recurring.class))
.createReaders()
.get(0);
assertThat(getAllFromReader(reader)).containsExactly(contactHistoryEntry);
assertThat(getAllFromReader(reader)).containsExactly(contactHistoryEntry.asHistoryEntry());
}
@Test
@ -287,11 +293,12 @@ class ChildEntityInputTest {
DomainBase domain = persistSimpleResource(newDomainBase(i + ".tld"));
historyEntries.add(
persistResource(
new HistoryEntry.Builder()
.setParent(domain)
.setModificationTime(now)
.setClientId(i + ".tld")
.build()));
new DomainHistory.Builder()
.setDomainContent(domain)
.setModificationTime(now)
.setClientId(i + ".tld")
.build())
.asHistoryEntry());
persistResource(EppResourceIndex.create(getBucketKey(i), Key.create(domain)));
}
Set<ImmutableObject> seen = new HashSet<>();
@ -333,7 +340,11 @@ class ChildEntityInputTest {
seen.add(deserializedReader.next());
seen.add(deserializedReader.next());
assertThat(seen)
.containsExactly(domainHistoryEntryA, contactHistoryEntry, oneTimeA, recurringA);
.containsExactly(
domainHistoryEntryA.asHistoryEntry(),
contactHistoryEntry.asHistoryEntry(),
oneTimeA,
recurringA);
assertThrows(NoSuchElementException.class, deserializedReader::next);
}
}

View file

@ -62,7 +62,7 @@ public class PollMessageExternalKeyConverterTest {
historyEntry =
persistResource(
new DomainHistory.Builder()
.setParent(persistActiveDomain("foo.foobar"))
.setDomainContent(persistActiveDomain("foo.foobar"))
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(Period.create(1, Period.Unit.YEARS))
.setXmlBytes("<xml></xml>".getBytes(UTF_8))

View file

@ -41,7 +41,7 @@ import org.junit.jupiter.api.BeforeEach;
class HistoryEntryDaoTest extends EntityTestCase {
private DomainBase domain;
private HistoryEntry historyEntry;
private HistoryEntry domainHistory;
@BeforeEach
void beforeEach() {
@ -55,10 +55,10 @@ class HistoryEntryDaoTest extends EntityTestCase {
.setReportField(TransactionReportField.NET_ADDS_1_YR)
.setReportAmount(1)
.build();
// Set up a new persisted HistoryEntry entity.
historyEntry =
// Set up a new persisted DomainHistory entity.
domainHistory =
new DomainHistory.Builder()
.setParent(domain)
.setDomainContent(domain)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(Period.create(1, Period.Unit.YEARS))
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
@ -71,14 +71,14 @@ class HistoryEntryDaoTest extends EntityTestCase {
.setRequestedByRegistrar(false)
.setDomainTransactionRecords(ImmutableSet.of(transactionRecord))
.build();
persistResource(historyEntry);
persistResource(domainHistory);
}
@TestOfyAndSql
void testSimpleLoadAll() {
assertThat(HistoryEntryDao.loadAllHistoryObjects(START_OF_TIME, END_OF_TIME))
.comparingElementsUsing(immutableObjectCorrespondence("nsHosts"))
.containsExactly(historyEntry);
.comparingElementsUsing(immutableObjectCorrespondence("nsHosts", "domainContent"))
.containsExactly(domainHistory);
}
@TestOfyAndSql
@ -99,8 +99,8 @@ class HistoryEntryDaoTest extends EntityTestCase {
transactIfJpaTm(
() ->
assertThat(HistoryEntryDao.loadHistoryObjectsForResource(domain.createVKey()))
.comparingElementsUsing(immutableObjectCorrespondence("nsHosts"))
.containsExactly(historyEntry));
.comparingElementsUsing(immutableObjectCorrespondence("nsHosts", "domainContent"))
.containsExactly(domainHistory));
}
@TestOfyAndSql

View file

@ -39,7 +39,7 @@ import org.junit.jupiter.api.BeforeEach;
@DualDatabaseTest
class HistoryEntryTest extends EntityTestCase {
private HistoryEntry historyEntry;
private DomainHistory domainHistory;
@BeforeEach
void setUp() {
@ -53,9 +53,9 @@ class HistoryEntryTest extends EntityTestCase {
.setReportAmount(1)
.build();
// Set up a new persisted HistoryEntry entity.
historyEntry =
domainHistory =
new DomainHistory.Builder()
.setParent(domain)
.setDomainContent(domain)
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setPeriod(Period.create(1, Period.Unit.YEARS))
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
@ -68,26 +68,27 @@ class HistoryEntryTest extends EntityTestCase {
.setRequestedByRegistrar(false)
.setDomainTransactionRecords(ImmutableSet.of(transactionRecord))
.build();
persistResource(historyEntry);
persistResource(domainHistory);
}
@TestOfyAndSql
void testPersistence() {
transactIfJpaTm(
() -> {
HistoryEntry fromDatabase = tm().loadByEntity(historyEntry);
HistoryEntry fromDatabase = tm().loadByEntity(domainHistory);
assertAboutImmutableObjects()
.that(fromDatabase)
.isEqualExceptFields(historyEntry, "nsHosts", "domainTransactionRecords");
.isEqualExceptFields(
domainHistory, "nsHosts", "domainTransactionRecords", "domainContent");
assertAboutImmutableObjects()
.that(Iterables.getOnlyElement(fromDatabase.getDomainTransactionRecords()))
.isEqualExceptFields(
Iterables.getOnlyElement(historyEntry.getDomainTransactionRecords()), "id");
Iterables.getOnlyElement(domainHistory.getDomainTransactionRecords()), "id");
});
}
@TestOfyOnly
void testIndexing() throws Exception {
verifyIndexing(historyEntry.asHistoryEntry(), "modificationTime", "clientId");
verifyIndexing(domainHistory.asHistoryEntry(), "modificationTime", "clientId");
}
}

View file

@ -224,7 +224,7 @@ public class DomainBaseToXjcConverterTest {
new DomainHistory.Builder()
.setModificationTime(clock.nowUtc())
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setParent(domain)
.setDomainContent(domain)
.build());
BillingEvent.OneTime billingEvent =
persistResource(

View file

@ -64,7 +64,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import com.google.common.net.InetAddresses;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.cmd.Saver;
import google.registry.dns.writer.VoidDnsWriter;
import google.registry.model.Buildable;
import google.registry.model.EppResource;
@ -124,6 +123,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.hibernate.Hibernate;
@ -642,7 +642,7 @@ public class DatabaseHelper {
new DomainHistory.Builder()
.setType(HistoryEntry.Type.DOMAIN_CREATE)
.setModificationTime(now)
.setParent(domain)
.setDomainContent(domain)
.build());
BillingEvent.Recurring autorenewEvent =
persistResource(
@ -683,7 +683,7 @@ public class DatabaseHelper {
new DomainHistory.Builder()
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST)
.setModificationTime(tm().transact(() -> tm().getTransactionTime()))
.setParent(domain)
.setDomainContent(domain)
.build());
BillingEvent.OneTime transferBillingEvent =
persistResource(
@ -1014,8 +1014,9 @@ public class DatabaseHelper {
private static <R> void saveResource(R resource, boolean wantBackup) {
if (tm().isOfy()) {
Saver saver = wantBackup || alwaysSaveWithBackup ? ofy().save() : ofy().saveWithoutBackup();
saver.entity(resource);
Consumer<Object> saver =
wantBackup || alwaysSaveWithBackup ? tm()::put : tm()::putWithoutBackup;
saver.accept(resource);
if (resource instanceof EppResource) {
EppResource eppResource = (EppResource) resource;
persistEppResourceExtras(
@ -1027,13 +1028,13 @@ public class DatabaseHelper {
}
private static <R extends EppResource> void persistEppResourceExtras(
R resource, EppResourceIndex index, Saver saver) {
R resource, EppResourceIndex index, Consumer<Object> saver) {
assertWithMessage("Cannot persist an EppResource with a missing repoId in tests")
.that(resource.getRepoId())
.isNotEmpty();
saver.entity(index);
saver.accept(index);
if (resource instanceof ForeignKeyedEppResource) {
saver.entity(ForeignKeyIndex.create(resource, resource.getDeletionTime()));
saver.accept(ForeignKeyIndex.create(resource, resource.getDeletionTime()));
}
}
@ -1058,8 +1059,8 @@ public class DatabaseHelper {
tm().transact(
() -> {
if (tm().isOfy()) {
Saver saver = ofy().save();
saver.entity(resource);
Consumer<Object> saver = tm()::put;
saver.accept(resource);
persistEppResourceExtras(resource, eppResourceIndex, saver);
} else {
tm().put(resource);

View file

@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadByEntity;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@ -225,7 +226,7 @@ class DedupeRecurringBillingEventIdsCommandTest
private static void assertNotChangeExceptUpdateTime(ImmutableObject... entities) {
for (ImmutableObject entity : entities) {
assertAboutImmutableObjects()
.that(ofy().load().entity(entity).now())
.that(loadByEntity(entity))
.isEqualExceptFields(entity, "updateTimestamp", "revisions");
}
}

View file

@ -108,7 +108,7 @@ class EppLifecycleToolsTest extends EppTestCase {
.atTime("2001-06-08T00:00:00Z")
.hasResponse("poll_response_unrenew.xml");
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-8-TLD-19-20-2001"))
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-9-TLD-20-21-2001"))
.atTime("2001-06-08T00:00:01Z")
.hasResponse("poll_ack_response_empty.xml");
@ -129,7 +129,7 @@ class EppLifecycleToolsTest extends EppTestCase {
.hasResponse(
"poll_response_autorenew.xml",
ImmutableMap.of(
"ID", "1-8-TLD-19-22-2003",
"ID", "1-9-TLD-20-23-2003",
"QDATE", "2003-06-01T00:02:00Z",
"DOMAIN", "example.tld",
"EXDATE", "2004-06-01T00:02:00Z"));

View file

@ -298,7 +298,7 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
new DomainHistory.Builder()
.setModificationTime(fakeClock.nowUtc())
.setType(DOMAIN_CREATE)
.setParent(domain)
.setDomainContent(domain)
.build());
BillingEvent.Recurring autorenewBillingEvent =
persistResource(

View file

@ -3,7 +3,7 @@
<result code="1301">
<msg>Command completed successfully; ack to dequeue</msg>
</result>
<msgQ count="1" id="1-8-TLD-19-20-2001">
<msgQ count="1" id="1-9-TLD-20-21-2001">
<qDate>2001-06-07T00:00:00Z</qDate>
<msg>Domain example.tld was unrenewed by 3 years; now expires at 2003-06-01T00:02:00.000Z.</msg>
</msgQ>

View file

@ -294,8 +294,8 @@ class google.registry.model.domain.GracePeriod {
google.registry.model.domain.rgp.GracePeriodStatus type;
google.registry.persistence.BillingVKey$BillingEventVKey billingEventOneTime;
google.registry.persistence.BillingVKey$BillingRecurrenceVKey billingEventRecurring;
java.lang.Long gracePeriodId;
java.lang.String clientId;
long gracePeriodId;
org.joda.time.DateTime expirationTime;
}
class google.registry.model.domain.Period {