Generate sql schema for BillingEvent (#565)

* Generate sql schema for BillingEvent

* Change to use sequence

* Address comments

* Resolve warnings and remove duplicate cost related fields

* Increase the flayway file version to V25

* Remove extra space

* Split to 3 tables, merge VKey

* Rename talbes

* Rename repoId to domainRepoId

* Exclude VKey in schema.txt

* Rename target_id to domain_name

* Fix javadoc

* Resolve comments
This commit is contained in:
Shicong Huang 2020-05-27 15:59:19 -04:00 committed by GitHub
parent bd443633f6
commit 26fb5388a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 941 additions and 179 deletions

View file

@ -155,7 +155,7 @@ public class ExpandRecurringBillingEventsActionTest
.setPeriodYears(1)
.setReason(Reason.RENEW)
.setSyntheticCreationTime(beginningOfTest)
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.setTargetId(domain.getFullyQualifiedDomainName());
}
@ -274,10 +274,12 @@ public class ExpandRecurringBillingEventsActionTest
.setParent(persistedEntries.get(0))
.build();
// Persist an otherwise identical billing event that differs only in recurring event key.
BillingEvent.OneTime persisted = expected.asBuilder()
.setParent(persistedEntries.get(1))
.setCancellationMatchingBillingEvent(Key.create(recurring2))
.build();
BillingEvent.OneTime persisted =
expected
.asBuilder()
.setParent(persistedEntries.get(1))
.setCancellationMatchingBillingEvent(recurring2.createVKey())
.build();
assertCursorAt(beginningOfTest);
assertBillingEventsForResource(domain, persisted, expected, recurring, recurring2);
}
@ -604,19 +606,21 @@ public class ExpandRecurringBillingEventsActionTest
assertHistoryEntryMatches(
domain, persistedEntries.get(0), "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"),
true);
BillingEvent.OneTime expected = defaultOneTimeBuilder()
.setParent(persistedEntries.get(0))
.setCancellationMatchingBillingEvent(Key.create(recurring))
.build();
BillingEvent.OneTime expected =
defaultOneTimeBuilder()
.setParent(persistedEntries.get(0))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.build();
assertHistoryEntryMatches(
domain, persistedEntries.get(1), "TheRegistrar", DateTime.parse("2000-05-20T00:00:00Z"),
true);
BillingEvent.OneTime expected2 = defaultOneTimeBuilder()
.setBillingTime(DateTime.parse("2000-05-20T00:00:00Z"))
.setEventTime(DateTime.parse("2000-04-05T00:00:00Z"))
.setParent(persistedEntries.get(1))
.setCancellationMatchingBillingEvent(Key.create(recurring2))
.build();
BillingEvent.OneTime expected2 =
defaultOneTimeBuilder()
.setBillingTime(DateTime.parse("2000-05-20T00:00:00Z"))
.setEventTime(DateTime.parse("2000-04-05T00:00:00Z"))
.setParent(persistedEntries.get(1))
.setCancellationMatchingBillingEvent(recurring2.createVKey())
.build();
assertBillingEventsForResource(domain, expected, expected2, recurring, recurring2);
assertCursorAt(beginningOfTest);
}

View file

@ -41,6 +41,7 @@ import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.monitoring.whitebox.EppMetric;
import google.registry.persistence.VKey;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
import google.registry.testing.FakeResponse;
@ -339,7 +340,8 @@ public class EppTestCase extends ShardableTestCase {
.setTargetId(domain.getFullyQualifiedDomainName())
.setClientId(domain.getCurrentSponsorClientId())
.setEventTime(deleteTime)
.setOneTimeEventKey(findKeyToActualOneTimeBillingEvent(billingEventToCancel))
.setOneTimeEventKey(
VKey.createOfy(OneTime.class, findKeyToActualOneTimeBillingEvent(billingEventToCancel)))
.setBillingTime(createTime.plus(Registry.get(domain.getTld()).getAddGracePeriodLength()))
.setReason(Reason.CREATE)
.setParent(getOnlyHistoryEntryOfType(domain, Type.DOMAIN_DELETE))
@ -353,7 +355,8 @@ public class EppTestCase extends ShardableTestCase {
.setTargetId(domain.getFullyQualifiedDomainName())
.setClientId(domain.getCurrentSponsorClientId())
.setEventTime(deleteTime)
.setOneTimeEventKey(findKeyToActualOneTimeBillingEvent(billingEventToCancel))
.setOneTimeEventKey(
VKey.createOfy(OneTime.class, findKeyToActualOneTimeBillingEvent(billingEventToCancel)))
.setBillingTime(renewTime.plus(Registry.get(domain.getTld()).getRenewGracePeriodLength()))
.setReason(Reason.RENEW)
.setParent(getOnlyHistoryEntryOfType(domain, Type.DOMAIN_DELETE))

View file

@ -276,7 +276,7 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow,
.setBillingTime(billingTime)
.setFlags(expectedBillingFlags)
.setParent(historyEntry)
.setAllocationToken(allocationToken == null ? null : Key.create(allocationToken))
.setAllocationToken(allocationToken == null ? null : allocationToken.createVKey())
.build();
BillingEvent.Recurring renewBillingEvent =

View file

@ -214,7 +214,7 @@ public class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow,
.setClientId("TheRegistrar")
.setEventTime(eventTime)
.setBillingTime(TIME_BEFORE_FLOW.plusDays(1))
.setOneTimeEventKey(Key.create(graceBillingEvent))
.setOneTimeEventKey(graceBillingEvent.createVKey())
.setParent(historyEntryDomainDelete)
.build());
}

View file

@ -71,6 +71,7 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import java.util.Arrays;
import java.util.stream.Stream;
import org.joda.money.Money;
@ -402,7 +403,8 @@ public class DomainTransferApproveFlowTest
.setEventTime(clock.nowUtc()) // The cancellation happens at the moment of transfer.
.setBillingTime(
oldExpirationTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()))
.setRecurringEventKey(domain.getAutorenewBillingEvent()));
.setRecurringEventKey(
VKey.createOfy(BillingEvent.Recurring.class, domain.getAutorenewBillingEvent())));
}
@Test

View file

@ -100,6 +100,7 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
import java.util.Map;
import java.util.Optional;
@ -1136,7 +1137,8 @@ public class DomainTransferRequestFlowTest
.setEventTime(clock.nowUtc().plus(Registry.get("tld").getAutomaticTransferLength()))
.setBillingTime(autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()))
// The cancellation should refer to the old autorenew billing event.
.setRecurringEventKey(existingAutorenewEvent));
.setRecurringEventKey(
VKey.createOfy(BillingEvent.Recurring.class, existingAutorenewEvent)));
}
@Test
@ -1164,7 +1166,8 @@ public class DomainTransferRequestFlowTest
.setBillingTime(
expirationTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()))
// The cancellation should refer to the old autorenew billing event.
.setRecurringEventKey(existingAutorenewEvent));
.setRecurringEventKey(
VKey.createOfy(BillingEvent.Recurring.class, existingAutorenewEvent)));
}
@Test

View file

@ -17,9 +17,11 @@ package google.registry.model.billing;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.SqlHelper.saveRegistrar;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static org.joda.money.CurrencyUnit.USD;
import static org.joda.time.DateTimeZone.UTC;
@ -37,19 +39,25 @@ import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.util.DateTimeUtils;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link BillingEvent}. */
public class BillingEventTest extends EntityTestCase {
private final DateTime now = DateTime.now(UTC);
public BillingEventTest() {
super(true);
}
HistoryEntry historyEntry;
HistoryEntry historyEntry2;
DomainBase domain;
BillingEvent.OneTime sqlOneTime;
BillingEvent.OneTime oneTime;
BillingEvent.OneTime oneTimeSynthetic;
BillingEvent.Recurring recurring;
@ -57,7 +65,7 @@ public class BillingEventTest extends EntityTestCase {
BillingEvent.Cancellation cancellationRecurring;
BillingEvent.Modification modification;
@Before
@BeforeEach
public void setUp() {
createTld("tld");
domain = persistActiveDomain("foo.tld");
@ -97,7 +105,18 @@ public class BillingEventTest extends EntityTestCase {
.setCost(Money.of(USD, 1))
.setEventTime(now)
.setBillingTime(now.plusDays(5))
.setAllocationToken(Key.create(allocationToken))));
.setAllocationToken(allocationToken.createVKey())));
sqlOneTime =
oneTime
.asBuilder()
.setDomainRepoId(domain.getRepoId())
.setDomainHistoryRevisionId(1L)
.setAllocationToken(
VKey.create(
AllocationToken.class, allocationToken.getToken(), Key.create(allocationToken)))
.build();
recurring =
persistResource(
commonInit(
@ -107,31 +126,41 @@ public class BillingEventTest extends EntityTestCase {
.setReason(Reason.RENEW)
.setEventTime(now.plusYears(1))
.setRecurrenceEndTime(END_OF_TIME)));
oneTimeSynthetic = persistResource(commonInit(
new BillingEvent.OneTime.Builder()
.setParent(historyEntry)
.setReason(Reason.CREATE)
.setFlags(ImmutableSet.of(BillingEvent.Flag.ANCHOR_TENANT, BillingEvent.Flag.SYNTHETIC))
.setSyntheticCreationTime(now.plusDays(10))
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setPeriodYears(2)
.setCost(Money.of(USD, 1))
.setEventTime(now)
.setBillingTime(now.plusDays(5))));
cancellationOneTime = persistResource(commonInit(
new BillingEvent.Cancellation.Builder()
.setParent(historyEntry2)
.setReason(Reason.CREATE)
.setEventTime(now.plusDays(1))
.setBillingTime(now.plusDays(5))
.setOneTimeEventKey(Key.create(oneTime))));
cancellationRecurring = persistResource(commonInit(
new BillingEvent.Cancellation.Builder()
.setParent(historyEntry2)
.setReason(Reason.RENEW)
.setEventTime(now.plusDays(1))
.setBillingTime(now.plusYears(1).plusDays(45))
.setRecurringEventKey(Key.create(recurring))));
oneTimeSynthetic =
persistResource(
commonInit(
new BillingEvent.OneTime.Builder()
.setParent(historyEntry)
.setReason(Reason.CREATE)
.setFlags(
ImmutableSet.of(
BillingEvent.Flag.ANCHOR_TENANT, BillingEvent.Flag.SYNTHETIC))
.setSyntheticCreationTime(now.plusDays(10))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.setPeriodYears(2)
.setCost(Money.of(USD, 1))
.setEventTime(now)
.setBillingTime(now.plusDays(5))));
cancellationOneTime =
persistResource(
commonInit(
new BillingEvent.Cancellation.Builder()
.setParent(historyEntry2)
.setReason(Reason.CREATE)
.setEventTime(now.plusDays(1))
.setBillingTime(now.plusDays(5))
.setOneTimeEventKey(oneTime.createVKey())));
cancellationRecurring =
persistResource(
commonInit(
new BillingEvent.Cancellation.Builder()
.setParent(historyEntry2)
.setReason(Reason.RENEW)
.setEventTime(now.plusDays(1))
.setBillingTime(now.plusYears(1).plusDays(45))
.setRecurringEventKey(recurring.createVKey())));
modification = persistResource(commonInit(
new BillingEvent.Modification.Builder()
.setParent(historyEntry2)
@ -149,6 +178,83 @@ public class BillingEventTest extends EntityTestCase {
.build();
}
private void saveNewBillingEvent(BillingEvent billingEvent) {
billingEvent.id = null;
jpaTm().transact(() -> jpaTm().saveNew(billingEvent));
}
@Test
public void testCloudSqlPersistence_OneTime() {
saveRegistrar("a registrar");
saveNewBillingEvent(sqlOneTime);
BillingEvent.OneTime persisted =
jpaTm()
.transact(
() -> jpaTm().load(VKey.createSql(BillingEvent.OneTime.class, sqlOneTime.id)));
// TODO(shicong): Remove these fixes after the entities are fully compatible
BillingEvent.OneTime fixed =
persisted
.asBuilder()
.setParent(sqlOneTime.getParentKey())
.setAllocationToken(sqlOneTime.getAllocationToken().get())
.build();
assertThat(fixed).isEqualTo(sqlOneTime);
}
@Test
public void testCloudSqlPersistence_Cancellation() {
saveRegistrar("a registrar");
saveNewBillingEvent(sqlOneTime);
VKey<BillingEvent.OneTime> sqlVKey = VKey.createSql(BillingEvent.OneTime.class, sqlOneTime.id);
BillingEvent sqlCancellationOneTime =
cancellationOneTime
.asBuilder()
.setOneTimeEventKey(sqlVKey)
.setDomainRepoId(domain.getRepoId())
.setDomainHistoryRevisionId(1L)
.build();
saveNewBillingEvent(sqlCancellationOneTime);
BillingEvent.Cancellation persisted =
jpaTm()
.transact(
() ->
jpaTm()
.load(
VKey.createSql(
BillingEvent.Cancellation.class, sqlCancellationOneTime.id)));
// TODO(shicong): Remove these fixes after the entities are fully compatible
BillingEvent.Cancellation fixed =
persisted
.asBuilder()
.setParent(sqlCancellationOneTime.getParentKey())
.setOneTimeEventKey(sqlVKey)
.build();
assertThat(fixed).isEqualTo(sqlCancellationOneTime);
}
@Test
public void testCloudSqlPersistence_Recurring() {
saveRegistrar("a registrar");
BillingEvent.Recurring sqlRecurring =
recurring
.asBuilder()
.setDomainRepoId(domain.getRepoId())
.setDomainHistoryRevisionId(1L)
.build();
saveNewBillingEvent(sqlRecurring);
BillingEvent.Recurring persisted =
jpaTm()
.transact(
() -> jpaTm().load(VKey.createSql(BillingEvent.Recurring.class, sqlRecurring.id)));
// TODO(shicong): Remove these fixes after the entities are fully compatible
BillingEvent.Recurring fixed =
persisted.asBuilder().setParent(sqlRecurring.getParentKey()).build();
assertThat(fixed).isEqualTo(sqlRecurring);
}
@Test
public void testPersistence() {
assertThat(ofy().load().entity(oneTime).now()).isEqualTo(oneTime);
@ -183,8 +289,13 @@ public class BillingEventTest extends EntityTestCase {
@Test
public void testCancellationMatching() {
Key<?> recurringKey = ofy().load().entity(oneTimeSynthetic).now()
.getCancellationMatchingBillingEvent();
Key<?> recurringKey =
ofy()
.load()
.entity(oneTimeSynthetic)
.now()
.getCancellationMatchingBillingEvent()
.getOfyKey();
assertThat(ofy().load().key(recurringKey).now()).isEqualTo(recurring);
}
@ -219,7 +330,7 @@ public class BillingEventTest extends EntityTestCase {
oneTime
.asBuilder()
.setFlags(ImmutableSet.of(BillingEvent.Flag.SYNTHETIC))
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.build());
assertThat(thrown)
.hasMessageThat()
@ -263,7 +374,7 @@ public class BillingEventTest extends EntityTestCase {
() ->
oneTime
.asBuilder()
.setCancellationMatchingBillingEvent(Key.create(recurring))
.setCancellationMatchingBillingEvent(recurring.createVKey())
.build());
assertThat(thrown)
.hasMessageThat()
@ -334,8 +445,8 @@ public class BillingEventTest extends EntityTestCase {
() ->
cancellationOneTime
.asBuilder()
.setOneTimeEventKey(Key.create(oneTime))
.setRecurringEventKey(Key.create(recurring))
.setOneTimeEventKey(oneTime.createVKey())
.setRecurringEventKey(recurring.createVKey())
.build());
assertThat(thrown).hasMessageThat().contains("exactly one billing event");
}

View file

@ -45,7 +45,7 @@ public class JpaEntityCoverage extends ExternalResource {
private static final ImmutableSet<Class> ALL_JPA_ENTITIES =
PersistenceXmlUtility.getManagedClasses().stream()
.filter(e -> !IGNORE_ENTITIES.contains(e.getSimpleName()))
.filter(e -> e.getAnnotation(Entity.class) != null)
.filter(e -> e.isAnnotationPresent(Entity.class))
.collect(ImmutableSet.toImmutableSet());
private static final Set<Class> allCoveredJpaEntities = Sets.newHashSet();
// Map of test class name to boolean flag indicating if it tests any JPA entities.

View file

@ -16,6 +16,7 @@ package google.registry.schema.integration;
import static com.google.common.truth.Truth.assert_;
import google.registry.model.billing.BillingEventTest;
import google.registry.model.contact.ContactResourceTest;
import google.registry.model.domain.DomainBaseSqlTest;
import google.registry.model.registry.RegistryLockDaoTest;
@ -68,6 +69,7 @@ import org.junit.runner.RunWith;
@SelectClasses({
// BeforeSuiteTest must be the first entry. See class javadoc for details.
BeforeSuiteTest.class,
BillingEventTest.class,
ClaimsListDaoTest.class,
ContactResourceTest.class,
CursorDaoTest.class,

View file

@ -5,11 +5,11 @@ class google.registry.model.UpdateAutoTimestamp {
org.joda.time.DateTime timestamp;
}
class google.registry.model.billing.BillingEvent$Cancellation {
@Id long id;
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
com.googlecode.objectify.Key<google.registry.model.billing.BillingEvent$OneTime> refOneTime;
com.googlecode.objectify.Key<google.registry.model.billing.BillingEvent$Recurring> refRecurring;
google.registry.model.billing.BillingEvent$Reason reason;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$OneTime> refOneTime;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> refRecurring;
java.lang.String clientId;
java.lang.String targetId;
java.util.Set<google.registry.model.billing.BillingEvent$Flag> flags;
@ -26,7 +26,7 @@ enum google.registry.model.billing.BillingEvent$Flag {
SYNTHETIC;
}
class google.registry.model.billing.BillingEvent$Modification {
@Id long id;
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
com.googlecode.objectify.Key<google.registry.model.billing.BillingEvent$OneTime> eventRef;
google.registry.model.billing.BillingEvent$Reason reason;
@ -38,11 +38,11 @@ class google.registry.model.billing.BillingEvent$Modification {
org.joda.time.DateTime eventTime;
}
class google.registry.model.billing.BillingEvent$OneTime {
@Id long id;
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
com.googlecode.objectify.Key<? extends google.registry.model.billing.BillingEvent> cancellationMatchingBillingEvent;
com.googlecode.objectify.Key<google.registry.model.domain.token.AllocationToken> allocationToken;
google.registry.model.billing.BillingEvent$Reason reason;
google.registry.persistence.VKey<? extends google.registry.model.billing.BillingEvent> cancellationMatchingBillingEvent;
google.registry.persistence.VKey<google.registry.model.domain.token.AllocationToken> allocationToken;
java.lang.Integer periodYears;
java.lang.String clientId;
java.lang.String targetId;
@ -62,7 +62,7 @@ enum google.registry.model.billing.BillingEvent$Reason {
TRANSFER;
}
class google.registry.model.billing.BillingEvent$Recurring {
@Id long id;
@Id java.lang.Long id;
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
google.registry.model.billing.BillingEvent$Reason reason;
google.registry.model.common.TimeOfYear recurrenceTimeOfYear;