mirror of
https://github.com/google/nomulus.git
synced 2025-05-14 08:27:14 +02:00
Parent recurring billing events under separate HistoryEntries
To log autorenews, we currently run a mapreduce daily that creates synthetic billing events for each recurring event past its due time. These are all parented under the original recurring event, which allows these synthetic events to incorrectly stack on the original mutating entry. We now explicitly create a new HistoryEntry of type DOMAIN_AUTORENEW to log autorenews alongside other mutating EPP flows. These also parent DomainTransactionRecords for the NET_RENEWS_1_YEAR field, with the reporting time equal to the billing time (which accounts for the autorenew grace period). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=166379700
This commit is contained in:
parent
a349893d3d
commit
7fb44e4f66
6 changed files with 216 additions and 230 deletions
|
@ -19,7 +19,9 @@ import static com.google.common.collect.Sets.difference;
|
||||||
import static google.registry.mapreduce.MapreduceRunner.PARAM_DRY_RUN;
|
import static google.registry.mapreduce.MapreduceRunner.PARAM_DRY_RUN;
|
||||||
import static google.registry.mapreduce.inputs.EppResourceInputs.createChildEntityInput;
|
import static google.registry.mapreduce.inputs.EppResourceInputs.createChildEntityInput;
|
||||||
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
||||||
|
import static google.registry.model.domain.Period.Unit.YEARS;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
|
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_AUTORENEW;
|
||||||
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
|
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
|
||||||
import static google.registry.util.CollectionUtils.union;
|
import static google.registry.util.CollectionUtils.union;
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
@ -42,13 +44,18 @@ import com.googlecode.objectify.VoidWork;
|
||||||
import com.googlecode.objectify.Work;
|
import com.googlecode.objectify.Work;
|
||||||
import google.registry.mapreduce.MapreduceRunner;
|
import google.registry.mapreduce.MapreduceRunner;
|
||||||
import google.registry.mapreduce.inputs.NullInput;
|
import google.registry.mapreduce.inputs.NullInput;
|
||||||
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.billing.BillingEvent;
|
import google.registry.model.billing.BillingEvent;
|
||||||
import google.registry.model.billing.BillingEvent.Flag;
|
import google.registry.model.billing.BillingEvent.Flag;
|
||||||
import google.registry.model.billing.BillingEvent.OneTime;
|
import google.registry.model.billing.BillingEvent.OneTime;
|
||||||
import google.registry.model.billing.BillingEvent.Recurring;
|
import google.registry.model.billing.BillingEvent.Recurring;
|
||||||
import google.registry.model.common.Cursor;
|
import google.registry.model.common.Cursor;
|
||||||
import google.registry.model.domain.DomainResource;
|
import google.registry.model.domain.DomainResource;
|
||||||
|
import google.registry.model.domain.Period;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
|
import google.registry.model.reporting.DomainTransactionRecord;
|
||||||
|
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||||
|
import google.registry.model.reporting.HistoryEntry;
|
||||||
import google.registry.request.Action;
|
import google.registry.request.Action;
|
||||||
import google.registry.request.Parameter;
|
import google.registry.request.Parameter;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
|
@ -59,6 +66,7 @@ import java.util.Set;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.money.Money;
|
import org.joda.money.Money;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapreduce that expands {@link Recurring} billing events into synthetic {@link OneTime} events.
|
* A mapreduce that expands {@link Recurring} billing events into synthetic {@link OneTime} events.
|
||||||
|
@ -174,9 +182,32 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
|
||||||
ImmutableSet<DateTime> existingBillingTimes =
|
ImmutableSet<DateTime> existingBillingTimes =
|
||||||
getExistingBillingTimes(oneTimesForDomain, recurring);
|
getExistingBillingTimes(oneTimesForDomain, recurring);
|
||||||
|
|
||||||
|
ImmutableSet.Builder<HistoryEntry> historyEntriesBuilder =
|
||||||
|
new ImmutableSet.Builder<>();
|
||||||
// Create synthetic OneTime events for all billing times that do not yet have an event
|
// Create synthetic OneTime events for all billing times that do not yet have an event
|
||||||
// persisted.
|
// persisted.
|
||||||
for (DateTime billingTime : difference(billingTimes, existingBillingTimes)) {
|
for (DateTime billingTime : difference(billingTimes, existingBillingTimes)) {
|
||||||
|
// Construct a new HistoryEntry that parents over the OneTime
|
||||||
|
HistoryEntry historyEntry = new HistoryEntry.Builder()
|
||||||
|
.setBySuperuser(false)
|
||||||
|
.setClientId(recurring.getClientId())
|
||||||
|
.setModificationTime(DateTime.now(DateTimeZone.UTC))
|
||||||
|
.setParent(recurring.getParentKey().getParent())
|
||||||
|
.setPeriod(Period.create(1, YEARS))
|
||||||
|
.setReason("Domain autorenewal by ExpandRecurringBillingEventsAction")
|
||||||
|
.setRequestedByRegistrar(false)
|
||||||
|
.setType(DOMAIN_AUTORENEW)
|
||||||
|
.setDomainTransactionRecords(
|
||||||
|
ImmutableSet.of(
|
||||||
|
DomainTransactionRecord.create(
|
||||||
|
tld.getTldStr(),
|
||||||
|
// We report this when the autorenew grace period ends
|
||||||
|
billingTime,
|
||||||
|
TransactionReportField.netRenewsFieldFromYears(1),
|
||||||
|
1)))
|
||||||
|
.build();
|
||||||
|
historyEntriesBuilder.add(historyEntry);
|
||||||
|
|
||||||
DateTime eventTime = billingTime.minus(tld.getAutoRenewGracePeriodLength());
|
DateTime eventTime = billingTime.minus(tld.getAutoRenewGracePeriodLength());
|
||||||
// Determine the cost for a one-year renewal.
|
// Determine the cost for a one-year renewal.
|
||||||
Money renewCost = getDomainRenewCost(recurring.getTargetId(), eventTime, 1);
|
Money renewCost = getDomainRenewCost(recurring.getTargetId(), eventTime, 1);
|
||||||
|
@ -186,7 +217,7 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
|
||||||
.setCost(renewCost)
|
.setCost(renewCost)
|
||||||
.setEventTime(eventTime)
|
.setEventTime(eventTime)
|
||||||
.setFlags(union(recurring.getFlags(), Flag.SYNTHETIC))
|
.setFlags(union(recurring.getFlags(), Flag.SYNTHETIC))
|
||||||
.setParent(recurring.getParentKey())
|
.setParent(historyEntry)
|
||||||
.setPeriodYears(1)
|
.setPeriodYears(1)
|
||||||
.setReason(recurring.getReason())
|
.setReason(recurring.getReason())
|
||||||
.setSyntheticCreationTime(executeTime)
|
.setSyntheticCreationTime(executeTime)
|
||||||
|
@ -194,9 +225,15 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
|
||||||
.setTargetId(recurring.getTargetId())
|
.setTargetId(recurring.getTargetId())
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
Set<HistoryEntry> historyEntries = historyEntriesBuilder.build();
|
||||||
Set<OneTime> syntheticOneTimes = syntheticOneTimesBuilder.build();
|
Set<OneTime> syntheticOneTimes = syntheticOneTimesBuilder.build();
|
||||||
if (!isDryRun) {
|
if (!isDryRun) {
|
||||||
ofy().save().entities(syntheticOneTimes).now();
|
ImmutableSet<ImmutableObject> entitiesToSave =
|
||||||
|
new ImmutableSet.Builder<ImmutableObject>()
|
||||||
|
.addAll(historyEntries)
|
||||||
|
.addAll(syntheticOneTimes)
|
||||||
|
.build();
|
||||||
|
ofy().save().entities(entitiesToSave).now();
|
||||||
}
|
}
|
||||||
return syntheticOneTimes.size();
|
return syntheticOneTimes.size();
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,11 @@ public class HistoryEntry extends ImmutableObject implements Buildable {
|
||||||
DOMAIN_APPLICATION_DELETE,
|
DOMAIN_APPLICATION_DELETE,
|
||||||
DOMAIN_APPLICATION_UPDATE,
|
DOMAIN_APPLICATION_UPDATE,
|
||||||
DOMAIN_APPLICATION_STATUS_UPDATE,
|
DOMAIN_APPLICATION_STATUS_UPDATE,
|
||||||
|
/**
|
||||||
|
* Used for domain registration autorenews explicitly logged by
|
||||||
|
* {@link google.registry.batch.ExpandRecurringBillingEventsAction}.
|
||||||
|
*/
|
||||||
|
DOMAIN_AUTORENEW,
|
||||||
DOMAIN_CREATE,
|
DOMAIN_CREATE,
|
||||||
DOMAIN_DELETE,
|
DOMAIN_DELETE,
|
||||||
DOMAIN_RENEW,
|
DOMAIN_RENEW,
|
||||||
|
|
|
@ -255,6 +255,7 @@ public class RdapJsonFormatter {
|
||||||
.put(HistoryEntry.Type.CONTACT_TRANSFER_APPROVE, RdapEventAction.TRANSFER)
|
.put(HistoryEntry.Type.CONTACT_TRANSFER_APPROVE, RdapEventAction.TRANSFER)
|
||||||
.put(HistoryEntry.Type.DOMAIN_APPLICATION_CREATE, RdapEventAction.REGISTRATION)
|
.put(HistoryEntry.Type.DOMAIN_APPLICATION_CREATE, RdapEventAction.REGISTRATION)
|
||||||
.put(HistoryEntry.Type.DOMAIN_APPLICATION_DELETE, RdapEventAction.DELETION)
|
.put(HistoryEntry.Type.DOMAIN_APPLICATION_DELETE, RdapEventAction.DELETION)
|
||||||
|
.put(HistoryEntry.Type.DOMAIN_AUTORENEW, RdapEventAction.REREGISTRATION)
|
||||||
.put(HistoryEntry.Type.DOMAIN_CREATE, RdapEventAction.REGISTRATION)
|
.put(HistoryEntry.Type.DOMAIN_CREATE, RdapEventAction.REGISTRATION)
|
||||||
.put(HistoryEntry.Type.DOMAIN_DELETE, RdapEventAction.DELETION)
|
.put(HistoryEntry.Type.DOMAIN_DELETE, RdapEventAction.DELETION)
|
||||||
.put(HistoryEntry.Type.DOMAIN_RENEW, RdapEventAction.REREGISTRATION)
|
.put(HistoryEntry.Type.DOMAIN_RENEW, RdapEventAction.REREGISTRATION)
|
||||||
|
|
|
@ -187,6 +187,7 @@ public class VerifyOteAction implements Runnable, JsonAction {
|
||||||
DOMAIN_APPLICATION_CREATES_SUNRISE(1, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE),
|
DOMAIN_APPLICATION_CREATES_SUNRISE(1, equalTo(Type.DOMAIN_APPLICATION_CREATE), IS_SUNRISE),
|
||||||
DOMAIN_APPLICATION_DELETES(2, equalTo(Type.DOMAIN_APPLICATION_DELETE)),
|
DOMAIN_APPLICATION_DELETES(2, equalTo(Type.DOMAIN_APPLICATION_DELETE)),
|
||||||
DOMAIN_APPLICATION_UPDATES(2, equalTo(Type.DOMAIN_APPLICATION_UPDATE)),
|
DOMAIN_APPLICATION_UPDATES(2, equalTo(Type.DOMAIN_APPLICATION_UPDATE)),
|
||||||
|
DOMAIN_AUTORENEWS(0, equalTo(Type.DOMAIN_AUTORENEW)),
|
||||||
DOMAIN_CREATES(0, equalTo(Type.DOMAIN_CREATE)),
|
DOMAIN_CREATES(0, equalTo(Type.DOMAIN_CREATE)),
|
||||||
DOMAIN_CREATES_ASCII(1, equalTo(Type.DOMAIN_CREATE), not(IS_IDN)),
|
DOMAIN_CREATES_ASCII(1, equalTo(Type.DOMAIN_CREATE), not(IS_IDN)),
|
||||||
DOMAIN_CREATES_IDN(1, equalTo(Type.DOMAIN_CREATE), IS_IDN),
|
DOMAIN_CREATES_IDN(1, equalTo(Type.DOMAIN_CREATE), IS_IDN),
|
||||||
|
|
|
@ -16,10 +16,14 @@ package google.registry.batch;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
||||||
|
import static google.registry.model.domain.Period.Unit.YEARS;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
|
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_AUTORENEW;
|
||||||
import static google.registry.testing.DatastoreHelper.assertBillingEvents;
|
import static google.registry.testing.DatastoreHelper.assertBillingEvents;
|
||||||
import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource;
|
import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource;
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
|
import static google.registry.testing.DatastoreHelper.getHistoryEntriesOfType;
|
||||||
|
import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
|
||||||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||||
import static google.registry.testing.DatastoreHelper.persistDeletedDomain;
|
import static google.registry.testing.DatastoreHelper.persistDeletedDomain;
|
||||||
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
||||||
|
@ -36,11 +40,15 @@ import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.VoidWork;
|
import com.googlecode.objectify.VoidWork;
|
||||||
import google.registry.model.billing.BillingEvent;
|
import google.registry.model.billing.BillingEvent;
|
||||||
import google.registry.model.billing.BillingEvent.Flag;
|
import google.registry.model.billing.BillingEvent.Flag;
|
||||||
|
import google.registry.model.billing.BillingEvent.OneTime;
|
||||||
import google.registry.model.billing.BillingEvent.Reason;
|
import google.registry.model.billing.BillingEvent.Reason;
|
||||||
import google.registry.model.common.Cursor;
|
import google.registry.model.common.Cursor;
|
||||||
import google.registry.model.domain.DomainResource;
|
import google.registry.model.domain.DomainResource;
|
||||||
|
import google.registry.model.domain.Period;
|
||||||
import google.registry.model.ofy.Ofy;
|
import google.registry.model.ofy.Ofy;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
|
import google.registry.model.reporting.DomainTransactionRecord;
|
||||||
|
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||||
import google.registry.model.reporting.HistoryEntry;
|
import google.registry.model.reporting.HistoryEntry;
|
||||||
import google.registry.testing.ExceptionRule;
|
import google.registry.testing.ExceptionRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
|
@ -118,24 +126,49 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
assertThat(cursor.getCursorTime()).isEqualTo(expectedCursorTime);
|
assertThat(cursor.getCursorTime()).isEqualTo(expectedCursorTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
void assertHistoryEntryMatches(
|
||||||
public void testSuccess_expandSingleEvent() throws Exception {
|
DomainResource domain, HistoryEntry actual, String clientId, DateTime billingTime) {
|
||||||
persistResource(recurring);
|
assertThat(actual.getBySuperuser()).isFalse();
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
assertThat(actual.getClientId()).isEqualTo(clientId);
|
||||||
runMapreduce();
|
assertThat(actual.getParent()).isEqualTo(Key.create(domain));
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
assertThat(actual.getPeriod()).isEqualTo(Period.create(1, YEARS));
|
||||||
// Default renew grace period of 45 days.
|
assertThat(actual.getReason())
|
||||||
|
.isEqualTo("Domain autorenewal by ExpandRecurringBillingEventsAction");
|
||||||
|
assertThat(actual.getRequestedByRegistrar()).isFalse();
|
||||||
|
assertThat(actual.getType()).isEqualTo(DOMAIN_AUTORENEW);
|
||||||
|
assertThat(actual.getDomainTransactionRecords())
|
||||||
|
.containsExactly(
|
||||||
|
DomainTransactionRecord.create(
|
||||||
|
"tld",
|
||||||
|
billingTime,
|
||||||
|
TransactionReportField.NET_RENEWS_1_YR,
|
||||||
|
1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private OneTime.Builder defaultOneTimeBuilder() {
|
||||||
|
return new BillingEvent.OneTime.Builder()
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
||||||
.setClientId("TheRegistrar")
|
.setClientId("TheRegistrar")
|
||||||
.setCost(Money.of(USD, 11))
|
.setCost(Money.of(USD, 11))
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
.setPeriodYears(1)
|
||||||
.setReason(Reason.RENEW)
|
.setReason(Reason.RENEW)
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
.setSyntheticCreationTime(beginningOfTest)
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
.setTargetId(domain.getFullyQualifiedDomainName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccess_expandSingleEvent() throws Exception {
|
||||||
|
persistResource(recurring);
|
||||||
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
|
runMapreduce();
|
||||||
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
|
assertHistoryEntryMatches(
|
||||||
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
|
.setParent(persistedEntry)
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(domain, expected, recurring);
|
assertBillingEventsForResource(domain, expected, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
|
@ -158,18 +191,11 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
.build());
|
.build());
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(deletedDomain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
deletedDomain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
.setClientId("TheRegistrar")
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
.setCost(Money.of(USD, 11))
|
.setParent(persistedEntry)
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(deletedDomain.getFullyQualifiedDomainName())
|
.setTargetId(deletedDomain.getFullyQualifiedDomainName())
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(deletedDomain, expected, recurring);
|
assertBillingEventsForResource(deletedDomain, expected, recurring);
|
||||||
|
@ -181,20 +207,10 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
.setClientId("TheRegistrar")
|
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
DateTime beginningOfSecondRun = clock.nowUtc();
|
DateTime beginningOfSecondRun = clock.nowUtc();
|
||||||
action.response = new FakeResponse();
|
action.response = new FakeResponse();
|
||||||
|
@ -206,50 +222,33 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_expandSingleEvent_idempotentForExistingOneTime() throws Exception {
|
public void testSuccess_expandSingleEvent_idempotentForExistingOneTime() throws Exception {
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
BillingEvent.OneTime persisted = persistResource(new BillingEvent.OneTime.Builder()
|
BillingEvent.OneTime persisted = persistResource(defaultOneTimeBuilder()
|
||||||
// Default renew grace period of 45 days.
|
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
|
||||||
.setClientId("TheRegistrar")
|
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
.setParent(historyEntry)
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build());
|
.build());
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
assertBillingEventsForResource(domain, persisted, recurring); // no additional billing events
|
// No additional billing events should be generated
|
||||||
|
assertBillingEventsForResource(domain, persisted, recurring);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_expandSingleEvent_notIdempotentForDifferentBillingTime()
|
public void testSuccess_expandSingleEvent_notIdempotentForDifferentBillingTime()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
runMapreduce();
|
||||||
.setClientId("TheRegistrar")
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
.setCost(Money.of(USD, 11))
|
assertHistoryEntryMatches(
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
|
||||||
// Persist an otherwise identical billing event that differs only in billing time.
|
// Persist an otherwise identical billing event that differs only in billing time.
|
||||||
BillingEvent.OneTime persisted = persistResource(expected.asBuilder()
|
BillingEvent.OneTime persisted = persistResource(expected.asBuilder()
|
||||||
.setBillingTime(DateTime.parse("1999-02-19T00:00:00Z"))
|
.setBillingTime(DateTime.parse("1999-02-19T00:00:00Z"))
|
||||||
.setEventTime(DateTime.parse("1999-01-05T00:00:00Z"))
|
.setEventTime(DateTime.parse("1999-01-05T00:00:00Z"))
|
||||||
.build());
|
.build());
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
|
||||||
runMapreduce();
|
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
assertBillingEventsForResource(domain, persisted, expected, recurring);
|
assertBillingEventsForResource(domain, persisted, expected, recurring);
|
||||||
}
|
}
|
||||||
|
@ -261,25 +260,23 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
BillingEvent.Recurring recurring2 = persistResource(recurring.asBuilder()
|
BillingEvent.Recurring recurring2 = persistResource(recurring.asBuilder()
|
||||||
.setId(3L)
|
.setId(3L)
|
||||||
.build());
|
.build());
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
|
||||||
.setClientId("TheRegistrar")
|
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
|
||||||
// Persist an otherwise identical billing event that differs only in recurring event key.
|
|
||||||
BillingEvent.OneTime persisted = persistResource(expected.asBuilder()
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring2))
|
|
||||||
.build());
|
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
List<HistoryEntry> persistedEntries =
|
||||||
|
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW);
|
||||||
|
for (HistoryEntry persistedEntry : persistedEntries) {
|
||||||
|
assertHistoryEntryMatches(
|
||||||
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
|
}
|
||||||
|
assertThat(persistedEntries).hasSize(2);
|
||||||
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
|
.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();
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
assertBillingEventsForResource(domain, persisted, expected, recurring, recurring2);
|
assertBillingEventsForResource(domain, persisted, expected, recurring, recurring2);
|
||||||
}
|
}
|
||||||
|
@ -292,6 +289,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
.build());
|
.build());
|
||||||
action.cursorTimeParam = Optional.of(DateTime.parse("2000-01-01T00:00:00Z"));
|
action.cursorTimeParam = Optional.of(DateTime.parse("2000-01-01T00:00:00Z"));
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
assertBillingEventsForResource(domain, recurring);
|
assertBillingEventsForResource(domain, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
}
|
}
|
||||||
|
@ -303,6 +302,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
.build());
|
.build());
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
assertBillingEventsForResource(domain, recurring);
|
assertBillingEventsForResource(domain, recurring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,20 +312,10 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
action.cursorTimeParam = Optional.of(DateTime.parse("2000-02-19T00:00:00Z"));
|
action.cursorTimeParam = Optional.of(DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
.setClientId("TheRegistrar")
|
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
|
||||||
assertBillingEventsForResource(domain, expected, recurring);
|
assertBillingEventsForResource(domain, expected, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
}
|
}
|
||||||
|
@ -335,20 +326,10 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
action.cursorTimeParam = Optional.of(DateTime.parse("2000-01-12T00:00:00Z"));
|
action.cursorTimeParam = Optional.of(DateTime.parse("2000-01-12T00:00:00Z"));
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
.setClientId("TheRegistrar")
|
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
|
||||||
assertBillingEventsForResource(domain, expected, recurring);
|
assertBillingEventsForResource(domain, expected, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
}
|
}
|
||||||
|
@ -361,6 +342,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
// Clock is advanced one milli in runMapreduce()
|
// Clock is advanced one milli in runMapreduce()
|
||||||
clock.setTo(testTime);
|
clock.setTo(testTime);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
// A candidate billing event is set to be billed exactly on 2/19/00 @ 00:00,
|
// A candidate billing event is set to be billed exactly on 2/19/00 @ 00:00,
|
||||||
// but these should not be generated as the interval is closed on cursorTime, open on
|
// but these should not be generated as the interval is closed on cursorTime, open on
|
||||||
// executeTime.
|
// executeTime.
|
||||||
|
@ -377,19 +360,14 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
recurring.asBuilder().setEventTime(recurring.getEventTime().plusYears(2)).build());
|
recurring.asBuilder().setEventTime(recurring.getEventTime().plusYears(2)).build());
|
||||||
clock.setTo(testTime);
|
clock.setTo(testTime);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2002-02-19T00:00:00Z"));
|
||||||
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
.setBillingTime(DateTime.parse("2002-02-19T00:00:00Z"))
|
.setBillingTime(DateTime.parse("2002-02-19T00:00:00Z"))
|
||||||
.setClientId("TheRegistrar")
|
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2002-01-05T00:00:00Z"))
|
.setEventTime(DateTime.parse("2002-01-05T00:00:00Z"))
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
.setParent(persistedEntry)
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(testTime)
|
.setSyntheticCreationTime(testTime)
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(domain, expected, recurring);
|
assertBillingEventsForResource(domain, expected, recurring);
|
||||||
assertCursorAt(testTime);
|
assertCursorAt(testTime);
|
||||||
|
@ -400,20 +378,10 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
saveCursor(START_OF_TIME);
|
saveCursor(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
.setClientId("TheRegistrar")
|
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
|
||||||
assertBillingEventsForResource(domain, expected, recurring);
|
assertBillingEventsForResource(domain, expected, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
}
|
}
|
||||||
|
@ -424,6 +392,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
// Simulate a quick second run of the mapreduce (this should be a no-op).
|
// Simulate a quick second run of the mapreduce (this should be a no-op).
|
||||||
saveCursor(clock.nowUtc().minusSeconds(1));
|
saveCursor(clock.nowUtc().minusSeconds(1));
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
assertBillingEventsForResource(domain, recurring);
|
assertBillingEventsForResource(domain, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
}
|
}
|
||||||
|
@ -436,6 +406,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
.build());
|
.build());
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
assertBillingEventsForResource(domain, recurring);
|
assertBillingEventsForResource(domain, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
}
|
}
|
||||||
|
@ -446,6 +418,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
action.isDryRun = true;
|
action.isDryRun = true;
|
||||||
saveCursor(START_OF_TIME); // Need a saved cursor to verify that it didn't move.
|
saveCursor(START_OF_TIME); // Need a saved cursor to verify that it didn't move.
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
assertBillingEventsForResource(domain, recurring);
|
assertBillingEventsForResource(domain, recurring);
|
||||||
assertCursorAt(START_OF_TIME); // Cursor doesn't move on a dry run.
|
assertCursorAt(START_OF_TIME); // Cursor doesn't move on a dry run.
|
||||||
}
|
}
|
||||||
|
@ -458,23 +432,23 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
expectedEvents.add(persistResource(recurring));
|
expectedEvents.add(persistResource(recurring));
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
List<HistoryEntry> persistedEntries =
|
||||||
|
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW);
|
||||||
|
assertThat(persistedEntries).hasSize(6);
|
||||||
DateTime eventDate = DateTime.parse("2000-01-05T00:00:00Z");
|
DateTime eventDate = DateTime.parse("2000-01-05T00:00:00Z");
|
||||||
// Default renew grace period of 45 days.
|
|
||||||
DateTime billingDate = DateTime.parse("2000-02-19T00:00:00Z");
|
DateTime billingDate = DateTime.parse("2000-02-19T00:00:00Z");
|
||||||
// Expecting events for '00, '01, '02, '03, '04, '05.
|
// Expecting events for '00, '01, '02, '03, '04, '05.
|
||||||
for (int year = 0; year < 6; year++) {
|
for (int year = 0; year < 6; year++) {
|
||||||
expectedEvents.add(new BillingEvent.OneTime.Builder()
|
assertHistoryEntryMatches(
|
||||||
|
domain,
|
||||||
|
persistedEntries.get(year),
|
||||||
|
"TheRegistrar",
|
||||||
|
billingDate.plusYears(year));
|
||||||
|
expectedEvents.add(defaultOneTimeBuilder()
|
||||||
.setBillingTime(billingDate.plusYears(year))
|
.setBillingTime(billingDate.plusYears(year))
|
||||||
.setClientId("TheRegistrar")
|
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(eventDate.plusYears(year))
|
.setEventTime(eventDate.plusYears(year))
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
.setParent(persistedEntries.get(year))
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(testTime)
|
.setSyntheticCreationTime(testTime)
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
assertBillingEventsForResource(domain, Iterables.toArray(expectedEvents, BillingEvent.class));
|
assertBillingEventsForResource(domain, Iterables.toArray(expectedEvents, BillingEvent.class));
|
||||||
|
@ -489,26 +463,24 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
expectedEvents.add(persistResource(recurring));
|
expectedEvents.add(persistResource(recurring));
|
||||||
saveCursor(DateTime.parse("2003-10-02T00:00:00Z"));
|
saveCursor(DateTime.parse("2003-10-02T00:00:00Z"));
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
List<HistoryEntry> persistedEntries =
|
||||||
|
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW);
|
||||||
|
assertThat(persistedEntries).hasSize(2);
|
||||||
DateTime eventDate = DateTime.parse("2004-01-05T00:00:00Z");
|
DateTime eventDate = DateTime.parse("2004-01-05T00:00:00Z");
|
||||||
// Default renew grace period of 45 days.
|
|
||||||
DateTime billingDate = DateTime.parse("2004-02-19T00:00:00Z");
|
DateTime billingDate = DateTime.parse("2004-02-19T00:00:00Z");
|
||||||
// Only expect the last two years' worth of billing events.
|
// Only expect the last two years' worth of billing events.
|
||||||
for (int year = 0; year < 2; year++) {
|
for (int year = 0; year < 2; year++) {
|
||||||
expectedEvents.add(new BillingEvent.OneTime.Builder()
|
assertHistoryEntryMatches(
|
||||||
|
domain, persistedEntries.get(year), "TheRegistrar", billingDate.plusYears(year));
|
||||||
|
expectedEvents.add(defaultOneTimeBuilder()
|
||||||
.setBillingTime(billingDate.plusYears(year))
|
.setBillingTime(billingDate.plusYears(year))
|
||||||
.setClientId("TheRegistrar")
|
.setParent(persistedEntries.get(year))
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(eventDate.plusYears(year))
|
.setEventTime(eventDate.plusYears(year))
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(testTime)
|
.setSyntheticCreationTime(testTime)
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
assertBillingEventsForResource(domain, Iterables.toArray(expectedEvents, BillingEvent.class));
|
assertBillingEventsForResource(
|
||||||
|
domain, Iterables.toArray(expectedEvents, BillingEvent.class));
|
||||||
assertCursorAt(testTime);
|
assertCursorAt(testTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,6 +491,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
assertBillingEventsForResource(domain, recurring);
|
assertBillingEventsForResource(domain, recurring);
|
||||||
assertCursorAt(testTime);
|
assertCursorAt(testTime);
|
||||||
}
|
}
|
||||||
|
@ -534,18 +508,13 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
.build());
|
.build());
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
|
assertHistoryEntryMatches(
|
||||||
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
||||||
.setClientId("TheRegistrar")
|
.setParent(persistedEntry)
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(testTime)
|
.setSyntheticCreationTime(testTime)
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(domain, recurring, expected);
|
assertBillingEventsForResource(domain, recurring, expected);
|
||||||
assertCursorAt(testTime);
|
assertCursorAt(testTime);
|
||||||
|
@ -558,19 +527,13 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
recurring.asBuilder().setEventTime(DateTime.parse("2000-01-15T00:00:00Z")).build());
|
recurring.asBuilder().setEventTime(DateTime.parse("2000-01-15T00:00:00Z")).build());
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-29T00:00:00Z"));
|
||||||
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
.setBillingTime(DateTime.parse("2000-02-29T00:00:00Z"))
|
.setBillingTime(DateTime.parse("2000-02-29T00:00:00Z"))
|
||||||
.setClientId("TheRegistrar")
|
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-01-15T00:00:00Z"))
|
.setEventTime(DateTime.parse("2000-01-15T00:00:00Z"))
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
.setParent(persistedEntry)
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(domain, expected, recurring);
|
assertBillingEventsForResource(domain, expected, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
|
@ -585,19 +548,14 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
clock.setTo(testTime);
|
clock.setTo(testTime);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2001-03-01T00:00:00Z"));
|
||||||
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
.setBillingTime(DateTime.parse("2001-03-01T00:00:00Z"))
|
.setBillingTime(DateTime.parse("2001-03-01T00:00:00Z"))
|
||||||
.setClientId("TheRegistrar")
|
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2001-01-15T00:00:00Z"))
|
.setEventTime(DateTime.parse("2001-01-15T00:00:00Z"))
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
.setParent(persistedEntry)
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(testTime)
|
.setSyntheticCreationTime(testTime)
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(domain, expected, recurring);
|
assertBillingEventsForResource(domain, expected, recurring);
|
||||||
assertCursorAt(testTime);
|
assertCursorAt(testTime);
|
||||||
|
@ -612,33 +570,21 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
.build());
|
.build());
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
List<HistoryEntry> persistedEntries = getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertThat(persistedEntries).hasSize(2);
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
assertHistoryEntryMatches(
|
||||||
.setClientId("TheRegistrar")
|
domain, persistedEntries.get(0), "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
.setCost(Money.of(USD, 11))
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
.setParent(persistedEntries.get(0))
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
.build();
|
||||||
BillingEvent.OneTime expected2 = new BillingEvent.OneTime.Builder()
|
assertHistoryEntryMatches(
|
||||||
// Default renew grace period of 45 days.
|
domain, persistedEntries.get(1), "TheRegistrar", DateTime.parse("2000-05-20T00:00:00Z"));
|
||||||
|
BillingEvent.OneTime expected2 = defaultOneTimeBuilder()
|
||||||
.setBillingTime(DateTime.parse("2000-05-20T00:00:00Z"))
|
.setBillingTime(DateTime.parse("2000-05-20T00:00:00Z"))
|
||||||
.setClientId("TheRegistrar")
|
|
||||||
.setCost(Money.of(USD, 11))
|
|
||||||
.setEventTime(DateTime.parse("2000-04-05T00:00:00Z"))
|
.setEventTime(DateTime.parse("2000-04-05T00:00:00Z"))
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
.setParent(persistedEntries.get(1))
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring2))
|
.setCancellationMatchingBillingEvent(Key.create(recurring2))
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(domain, expected, expected2, recurring, recurring2);
|
assertBillingEventsForResource(domain, expected, expected2, recurring, recurring2);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
|
@ -654,19 +600,12 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder()
|
HistoryEntry persistedEntry = getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW);
|
||||||
// Default renew grace period of 45 days.
|
assertHistoryEntryMatches(
|
||||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"));
|
||||||
.setClientId("TheRegistrar")
|
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||||
|
.setParent(persistedEntry)
|
||||||
.setCost(Money.of(USD, 100))
|
.setCost(Money.of(USD, 100))
|
||||||
.setEventTime(DateTime.parse("2000-01-05T00:00:00Z"))
|
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
|
||||||
.setParent(historyEntry)
|
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(beginningOfTest)
|
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(domain, expected, recurring);
|
assertBillingEventsForResource(domain, expected, recurring);
|
||||||
assertCursorAt(beginningOfTest);
|
assertCursorAt(beginningOfTest);
|
||||||
|
@ -687,26 +626,26 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
persistResource(recurring);
|
persistResource(recurring);
|
||||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
List<HistoryEntry> persistedEntries =
|
||||||
|
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW);
|
||||||
|
assertThat(persistedEntries).hasSize(2);
|
||||||
DateTime eventDate = DateTime.parse("2000-01-05T00:00:00Z");
|
DateTime eventDate = DateTime.parse("2000-01-05T00:00:00Z");
|
||||||
// Default renew grace period of 45 days.
|
|
||||||
DateTime billingDate = DateTime.parse("2000-02-19T00:00:00Z");
|
DateTime billingDate = DateTime.parse("2000-02-19T00:00:00Z");
|
||||||
BillingEvent.OneTime cheaper = new BillingEvent.OneTime.Builder()
|
assertHistoryEntryMatches(domain, persistedEntries.get(0), "TheRegistrar", billingDate);
|
||||||
|
BillingEvent.OneTime cheaper = defaultOneTimeBuilder()
|
||||||
.setBillingTime(billingDate)
|
.setBillingTime(billingDate)
|
||||||
.setClientId("TheRegistrar")
|
|
||||||
.setCost(Money.of(USD, 8))
|
|
||||||
.setEventTime(eventDate)
|
.setEventTime(eventDate)
|
||||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
.setParent(persistedEntries.get(0))
|
||||||
.setParent(historyEntry)
|
.setCost(Money.of(USD, 8))
|
||||||
.setPeriodYears(1)
|
|
||||||
.setReason(Reason.RENEW)
|
|
||||||
.setSyntheticCreationTime(testTime)
|
.setSyntheticCreationTime(testTime)
|
||||||
.setCancellationMatchingBillingEvent(Key.create(recurring))
|
|
||||||
.setTargetId(domain.getFullyQualifiedDomainName())
|
|
||||||
.build();
|
.build();
|
||||||
|
assertHistoryEntryMatches(
|
||||||
|
domain, persistedEntries.get(1), "TheRegistrar", billingDate.plusYears(1));
|
||||||
BillingEvent.OneTime expensive = cheaper.asBuilder()
|
BillingEvent.OneTime expensive = cheaper.asBuilder()
|
||||||
.setCost(Money.of(USD, 10))
|
.setCost(Money.of(USD, 10))
|
||||||
.setBillingTime(billingDate.plusYears(1))
|
.setBillingTime(billingDate.plusYears(1))
|
||||||
.setEventTime(eventDate.plusYears(1))
|
.setEventTime(eventDate.plusYears(1))
|
||||||
|
.setParent(persistedEntries.get(1))
|
||||||
.build();
|
.build();
|
||||||
assertBillingEventsForResource(domain, recurring, cheaper, expensive);
|
assertBillingEventsForResource(domain, recurring, cheaper, expensive);
|
||||||
assertCursorAt(testTime);
|
assertCursorAt(testTime);
|
||||||
|
@ -735,6 +674,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
// Set target to a TLD that doesn't exist.
|
// Set target to a TLD that doesn't exist.
|
||||||
recurring = persistResource(recurring.asBuilder().setTargetId("domain.junk").build());
|
recurring = persistResource(recurring.asBuilder().setTargetId("domain.junk").build());
|
||||||
runMapreduce();
|
runMapreduce();
|
||||||
|
// No new history entries should be generated
|
||||||
|
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||||
assertBillingEvents(recurring); // only the bogus one in Datastore
|
assertBillingEvents(recurring); // only the bogus one in Datastore
|
||||||
assertCursorAt(START_OF_TIME); // Cursor doesn't move on a failure.
|
assertCursorAt(START_OF_TIME); // Cursor doesn't move on a failure.
|
||||||
}
|
}
|
||||||
|
|
|
@ -846,6 +846,7 @@ enum google.registry.model.reporting.HistoryEntry$Type {
|
||||||
DOMAIN_APPLICATION_DELETE;
|
DOMAIN_APPLICATION_DELETE;
|
||||||
DOMAIN_APPLICATION_STATUS_UPDATE;
|
DOMAIN_APPLICATION_STATUS_UPDATE;
|
||||||
DOMAIN_APPLICATION_UPDATE;
|
DOMAIN_APPLICATION_UPDATE;
|
||||||
|
DOMAIN_AUTORENEW;
|
||||||
DOMAIN_CREATE;
|
DOMAIN_CREATE;
|
||||||
DOMAIN_DELETE;
|
DOMAIN_DELETE;
|
||||||
DOMAIN_RENEW;
|
DOMAIN_RENEW;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue