mirror of
https://github.com/google/nomulus
synced 2026-02-10 06:50:30 +00:00
Make ExpandRecurringBillingEventAction SQL-aware (#1181)
There is some complication regarding how the CancellationMatchingBillingEvent of the generated OneTime can be reconstructed when loading from SQL. I decided to only address it in testing as there is no real value to fully reconstruct this VKey in production where we are either in SQL or Ofy mode, both never in both. Therefore the VKey in a particular mode only needs to contain the corresponding key in order to function. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1181) <!-- Reviewable:end -->
This commit is contained in:
@@ -21,6 +21,7 @@ import static google.registry.model.ofy.ObjectifyService.auditedOfy;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_AUTORENEW;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.testing.DatabaseHelper.assertBillingEvents;
|
||||
import static google.registry.testing.DatabaseHelper.assertBillingEventsForResource;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
@@ -52,9 +53,14 @@ 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.testing.DualDatabaseTest;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.InjectExtension;
|
||||
import google.registry.testing.ReplayExtension;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import google.registry.testing.TestOfyOnly;
|
||||
import google.registry.testing.TestSqlOnly;
|
||||
import google.registry.testing.mapreduce.MapreduceTestCase;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -62,17 +68,25 @@ import java.util.Optional;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link ExpandRecurringBillingEventsAction}. */
|
||||
@DualDatabaseTest
|
||||
public class ExpandRecurringBillingEventsActionTest
|
||||
extends MapreduceTestCase<ExpandRecurringBillingEventsAction> {
|
||||
|
||||
@RegisterExtension public final InjectExtension inject = new InjectExtension();
|
||||
private DateTime currentTestTime = DateTime.parse("1999-01-05T00:00:00Z");
|
||||
private final FakeClock clock = new FakeClock(currentTestTime);
|
||||
|
||||
private final DateTime beginningOfTest = DateTime.parse("2000-10-02T00:00:00Z");
|
||||
private final FakeClock clock = new FakeClock(beginningOfTest);
|
||||
@Order(Order.DEFAULT - 1)
|
||||
@RegisterExtension
|
||||
public final InjectExtension inject =
|
||||
new InjectExtension().withStaticFieldOverride(Ofy.class, "clock", clock);
|
||||
|
||||
@Order(Order.DEFAULT - 2)
|
||||
@RegisterExtension
|
||||
public final ReplayExtension replayExtension = ReplayExtension.createWithCompare(clock);
|
||||
|
||||
private DomainBase domain;
|
||||
private DomainHistory historyEntry;
|
||||
@@ -80,7 +94,6 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
action = new ExpandRecurringBillingEventsAction();
|
||||
action.mrRunner = makeDefaultRunner();
|
||||
action.clock = clock;
|
||||
@@ -111,27 +124,37 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setTargetId(domain.getDomainName())
|
||||
.build();
|
||||
currentTestTime = clock.nowUtc();
|
||||
clock.setTo(DateTime.parse("2000-10-02T00:00:00Z"));
|
||||
}
|
||||
|
||||
private void saveCursor(final DateTime cursorTime) {
|
||||
tm().transact(() -> tm().put(Cursor.createGlobal(RECURRING_BILLING, cursorTime)));
|
||||
}
|
||||
|
||||
private void runMapreduce() throws Exception {
|
||||
private void runAction() throws Exception {
|
||||
action.response = new FakeResponse();
|
||||
action.run();
|
||||
// Need to save the current test time before running the mapreduce, which increments the clock.
|
||||
// The execution time (e. g. transaction time) is captured when the action starts running so
|
||||
// the passage of time afterward does not affect the timestamp stored in the billing events.
|
||||
currentTestTime = clock.nowUtc();
|
||||
executeTasksUntilEmpty("mapreduce", clock);
|
||||
auditedOfy().clearSessionCache();
|
||||
}
|
||||
|
||||
private void assertCursorAt(DateTime expectedCursorTime) {
|
||||
Cursor cursor = auditedOfy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now();
|
||||
Cursor cursor =
|
||||
transactIfJpaTm(() -> tm().loadByKey(Cursor.createGlobalVKey(RECURRING_BILLING)));
|
||||
assertThat(cursor).isNotNull();
|
||||
assertThat(cursor.getCursorTime()).isEqualTo(expectedCursorTime);
|
||||
}
|
||||
|
||||
private void assertHistoryEntryMatches(
|
||||
DomainBase domain, HistoryEntry actual, String clientId, DateTime billingTime,
|
||||
DomainBase domain,
|
||||
HistoryEntry actual,
|
||||
String clientId,
|
||||
DateTime billingTime,
|
||||
boolean shouldHaveTxRecord) {
|
||||
assertThat(actual.getBySuperuser()).isFalse();
|
||||
assertThat(actual.getClientId()).isEqualTo(clientId);
|
||||
@@ -145,10 +168,7 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
assertThat(actual.getDomainTransactionRecords())
|
||||
.containsExactly(
|
||||
DomainTransactionRecord.create(
|
||||
"tld",
|
||||
billingTime,
|
||||
TransactionReportField.NET_RENEWS_1_YR,
|
||||
1));
|
||||
"tld", billingTime, TransactionReportField.NET_RENEWS_1_YR, 1));
|
||||
} else {
|
||||
assertThat(actual.getDomainTransactionRecords()).isEmpty();
|
||||
}
|
||||
@@ -163,28 +183,26 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW, Flag.SYNTHETIC))
|
||||
.setPeriodYears(1)
|
||||
.setReason(Reason.RENEW)
|
||||
.setSyntheticCreationTime(beginningOfTest)
|
||||
.setSyntheticCreationTime(currentTestTime)
|
||||
.setCancellationMatchingBillingEvent(recurring.createVKey())
|
||||
.setTargetId(domain.getDomainName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent() throws Exception {
|
||||
persistResource(recurring);
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||
.setParent(persistedEntry)
|
||||
.build();
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_deletedDomain() throws Exception {
|
||||
DateTime deletionTime = DateTime.parse("2000-08-01T00:00:00Z");
|
||||
DomainBase deletedDomain = persistDeletedDomain("deleted.tld", deletionTime);
|
||||
@@ -209,7 +227,7 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.setTargetId(deletedDomain.getDomainName())
|
||||
.build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(deletedDomain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
@@ -224,69 +242,69 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.setTargetId(deletedDomain.getDomainName())
|
||||
.build();
|
||||
assertBillingEventsForResource(deletedDomain, expected, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_idempotentForDuplicateRuns() throws Exception {
|
||||
persistResource(recurring);
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
DateTime beginningOfSecondRun = clock.nowUtc();
|
||||
action.response = new FakeResponse();
|
||||
runMapreduce();
|
||||
runAction();
|
||||
assertCursorAt(beginningOfSecondRun);
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_idempotentForExistingOneTime() throws Exception {
|
||||
persistResource(recurring);
|
||||
BillingEvent.OneTime persisted = persistResource(defaultOneTimeBuilder()
|
||||
.setParent(historyEntry)
|
||||
.build());
|
||||
BillingEvent.OneTime persisted =
|
||||
persistResource(defaultOneTimeBuilder().setParent(historyEntry).build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
// No new history entries should be generated
|
||||
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
// No additional billing events should be generated
|
||||
assertBillingEventsForResource(domain, persisted, recurring);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestSqlOnly
|
||||
void testSuccess_expandSingleEvent_notIdempotentForDifferentBillingTime() throws Exception {
|
||||
persistResource(recurring);
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||
// Persist an otherwise identical billing event that differs only in billing time.
|
||||
BillingEvent.OneTime persisted = persistResource(expected.asBuilder()
|
||||
.setBillingTime(DateTime.parse("1999-02-19T00:00:00Z"))
|
||||
.setEventTime(DateTime.parse("1999-01-05T00:00:00Z"))
|
||||
.build());
|
||||
assertCursorAt(beginningOfTest);
|
||||
BillingEvent.OneTime persisted =
|
||||
persistResource(
|
||||
expected
|
||||
.asBuilder()
|
||||
.setBillingTime(DateTime.parse("1999-02-19T00:00:00Z"))
|
||||
.setEventTime(DateTime.parse("1999-01-05T00:00:00Z"))
|
||||
.build());
|
||||
assertCursorAt(currentTestTime);
|
||||
assertBillingEventsForResource(domain, persisted, expected, recurring);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_notIdempotentForDifferentRecurring() throws Exception {
|
||||
persistResource(recurring);
|
||||
BillingEvent.Recurring recurring2 = persistResource(recurring.asBuilder()
|
||||
.setId(3L)
|
||||
.build());
|
||||
BillingEvent.Recurring recurring2 = persistResource(recurring.asBuilder().setId(3L).build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
List<DomainHistory> persistedEntries =
|
||||
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
for (HistoryEntry persistedEntry : persistedEntries) {
|
||||
@@ -294,9 +312,8 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
}
|
||||
assertThat(persistedEntries).hasSize(2);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||
.setParent(persistedEntries.get(0))
|
||||
.build();
|
||||
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
|
||||
@@ -304,164 +321,166 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.setParent(persistedEntries.get(1))
|
||||
.setCancellationMatchingBillingEvent(recurring2.createVKey())
|
||||
.build();
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
assertBillingEventsForResource(domain, persisted, expected, recurring, recurring2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_ignoreRecurringBeforeWindow() throws Exception {
|
||||
recurring = persistResource(recurring.asBuilder()
|
||||
.setEventTime(DateTime.parse("1997-01-05T00:00:00Z"))
|
||||
.setRecurrenceEndTime(DateTime.parse("1999-10-05T00:00:00Z"))
|
||||
.build());
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setEventTime(DateTime.parse("1997-01-05T00:00:00Z"))
|
||||
.setRecurrenceEndTime(DateTime.parse("1999-10-05T00:00:00Z"))
|
||||
.build());
|
||||
action.cursorTimeParam = Optional.of(DateTime.parse("2000-01-01T00:00:00Z"));
|
||||
runMapreduce();
|
||||
runAction();
|
||||
// No new history entries should be generated
|
||||
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||
assertBillingEventsForResource(domain, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_ignoreRecurringAfterWindow() throws Exception {
|
||||
recurring = persistResource(recurring.asBuilder()
|
||||
.setEventTime(clock.nowUtc().plusYears(2))
|
||||
.build());
|
||||
recurring =
|
||||
persistResource(recurring.asBuilder().setEventTime(clock.nowUtc().plusYears(2)).build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
// No new history entries should be generated
|
||||
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||
assertBillingEventsForResource(domain, recurring);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_billingTimeAtCursorTime() throws Exception {
|
||||
persistResource(recurring);
|
||||
action.cursorTimeParam = Optional.of(DateTime.parse("2000-02-19T00:00:00Z"));
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_cursorTimeBetweenEventAndBillingTime() throws Exception {
|
||||
persistResource(recurring);
|
||||
action.cursorTimeParam = Optional.of(DateTime.parse("2000-01-12T00:00:00Z"));
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_billingTimeAtExecutionTime() throws Exception {
|
||||
DateTime testTime = DateTime.parse("2000-02-19T00:00:00Z").minusMillis(1);
|
||||
clock.setTo(currentTestTime);
|
||||
persistResource(recurring);
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
// Clock is advanced one milli in runMapreduce()
|
||||
clock.setTo(testTime);
|
||||
runMapreduce();
|
||||
clock.setTo(DateTime.parse("2000-02-19T00:00:00Z"));
|
||||
runAction();
|
||||
// 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,
|
||||
// but these should not be generated as the interval is closed on cursorTime, open on
|
||||
// executeTime.
|
||||
assertBillingEventsForResource(domain, recurring);
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_multipleYearCreate() throws Exception {
|
||||
DateTime testTime = beginningOfTest.plusYears(2);
|
||||
action.cursorTimeParam = Optional.of(recurring.getEventTime());
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring.asBuilder().setEventTime(recurring.getEventTime().plusYears(2)).build());
|
||||
clock.setTo(testTime);
|
||||
runMapreduce();
|
||||
clock.setTo(DateTime.parse("2002-10-02T00:00:00Z"));
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2002-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2002-02-19T00:00:00Z"))
|
||||
.setEventTime(DateTime.parse("2002-01-05T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.setSyntheticCreationTime(testTime)
|
||||
.build();
|
||||
BillingEvent.OneTime expected =
|
||||
defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2002-02-19T00:00:00Z"))
|
||||
.setEventTime(DateTime.parse("2002-01-05T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.build();
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_withCursor() throws Exception {
|
||||
persistResource(recurring);
|
||||
saveCursor(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder().setParent(persistedEntry).build();
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_withCursorPastExpected() throws Exception {
|
||||
persistResource(recurring);
|
||||
// Simulate a quick second run of the mapreduce (this should be a no-op).
|
||||
saveCursor(clock.nowUtc().minusSeconds(1));
|
||||
runMapreduce();
|
||||
runAction();
|
||||
// No new history entries should be generated
|
||||
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||
assertBillingEventsForResource(domain, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_recurrenceEndBeforeEvent() throws Exception {
|
||||
// This can occur when a domain is transferred or deleted before a domain comes up for renewal.
|
||||
recurring = persistResource(recurring.asBuilder()
|
||||
.setRecurrenceEndTime(recurring.getEventTime().minusDays(5))
|
||||
.build());
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setRecurrenceEndTime(recurring.getEventTime().minusDays(5))
|
||||
.build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
// No new history entries should be generated
|
||||
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||
assertBillingEventsForResource(domain, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_dryRun() throws Exception {
|
||||
persistResource(recurring);
|
||||
action.isDryRun = true;
|
||||
saveCursor(START_OF_TIME); // Need a saved cursor to verify that it didn't move.
|
||||
runMapreduce();
|
||||
runAction();
|
||||
// No new history entries should be generated
|
||||
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||
assertBillingEventsForResource(domain, recurring);
|
||||
assertCursorAt(START_OF_TIME); // Cursor doesn't move on a dry run.
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_multipleYears() throws Exception {
|
||||
DateTime testTime = clock.nowUtc().plusYears(5);
|
||||
clock.setTo(testTime);
|
||||
clock.setTo(clock.nowUtc().plusYears(5));
|
||||
List<BillingEvent> expectedEvents = new ArrayList<>();
|
||||
expectedEvents.add(persistResource(recurring));
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
List<DomainHistory> persistedEntries =
|
||||
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertThat(persistedEntries).hasSize(6);
|
||||
@@ -470,29 +489,25 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
// Expecting events for '00, '01, '02, '03, '04, '05.
|
||||
for (int year = 0; year < 6; year++) {
|
||||
assertHistoryEntryMatches(
|
||||
domain,
|
||||
persistedEntries.get(year),
|
||||
"TheRegistrar",
|
||||
billingDate.plusYears(year), true);
|
||||
expectedEvents.add(defaultOneTimeBuilder()
|
||||
.setBillingTime(billingDate.plusYears(year))
|
||||
.setEventTime(eventDate.plusYears(year))
|
||||
.setParent(persistedEntries.get(year))
|
||||
.setSyntheticCreationTime(testTime)
|
||||
.build());
|
||||
domain, persistedEntries.get(year), "TheRegistrar", billingDate.plusYears(year), true);
|
||||
expectedEvents.add(
|
||||
defaultOneTimeBuilder()
|
||||
.setBillingTime(billingDate.plusYears(year))
|
||||
.setEventTime(eventDate.plusYears(year))
|
||||
.setParent(persistedEntries.get(year))
|
||||
.build());
|
||||
}
|
||||
assertBillingEventsForResource(domain, Iterables.toArray(expectedEvents, BillingEvent.class));
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_multipleYears_cursorInBetweenYears() throws Exception {
|
||||
DateTime testTime = clock.nowUtc().plusYears(5);
|
||||
clock.setTo(testTime);
|
||||
clock.setTo(clock.nowUtc().plusYears(5));
|
||||
List<BillingEvent> expectedEvents = new ArrayList<>();
|
||||
expectedEvents.add(persistResource(recurring));
|
||||
saveCursor(DateTime.parse("2003-10-02T00:00:00Z"));
|
||||
runMapreduce();
|
||||
runAction();
|
||||
List<DomainHistory> persistedEntries =
|
||||
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertThat(persistedEntries).hasSize(2);
|
||||
@@ -502,139 +517,153 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
for (int year = 0; year < 2; year++) {
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntries.get(year), "TheRegistrar", billingDate.plusYears(year), true);
|
||||
expectedEvents.add(defaultOneTimeBuilder()
|
||||
.setBillingTime(billingDate.plusYears(year))
|
||||
.setParent(persistedEntries.get(year))
|
||||
.setEventTime(eventDate.plusYears(year))
|
||||
.setSyntheticCreationTime(testTime)
|
||||
.build());
|
||||
expectedEvents.add(
|
||||
defaultOneTimeBuilder()
|
||||
.setBillingTime(billingDate.plusYears(year))
|
||||
.setParent(persistedEntries.get(year))
|
||||
.setEventTime(eventDate.plusYears(year))
|
||||
.build());
|
||||
}
|
||||
assertBillingEventsForResource(domain, Iterables.toArray(expectedEvents, BillingEvent.class));
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_singleEvent_beforeRenewal() throws Exception {
|
||||
DateTime testTime = DateTime.parse("2000-01-04T00:00:00Z");
|
||||
clock.setTo(testTime);
|
||||
// Need to restore to the time before the clock was advanced so that the commit log's timestamp
|
||||
// is not inverted when the clock is later reverted.
|
||||
clock.setTo(currentTestTime);
|
||||
persistResource(recurring);
|
||||
clock.setTo(DateTime.parse("2000-01-04T00:00:00Z"));
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
// No new history entries should be generated
|
||||
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||
assertBillingEventsForResource(domain, recurring);
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_singleEvent_afterRecurrenceEnd_inAutorenewGracePeriod() throws Exception {
|
||||
// The domain creation date is 1999-01-05, and the first renewal date is thus 2000-01-05.
|
||||
DateTime testTime = DateTime.parse("2001-02-06T00:00:00Z");
|
||||
clock.setTo(testTime);
|
||||
recurring = persistResource(recurring.asBuilder()
|
||||
// The domain deletion date is 2000-01-29, which is within the 45 day autorenew grace period
|
||||
// from the renewal date.
|
||||
.setRecurrenceEndTime(DateTime.parse("2000-01-29T00:00:00Z"))
|
||||
.setEventTime(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
clock.setTo(DateTime.parse("2001-02-06T00:00:00Z"));
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring
|
||||
.asBuilder()
|
||||
// The domain deletion date is 2000-01-29, which is within the 45 day autorenew
|
||||
// grace period
|
||||
// from the renewal date.
|
||||
.setRecurrenceEndTime(DateTime.parse("2000-01-29T00:00:00Z"))
|
||||
.setEventTime(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), false);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.setSyntheticCreationTime(testTime)
|
||||
.build();
|
||||
BillingEvent.OneTime expected =
|
||||
defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.build();
|
||||
assertBillingEventsForResource(domain, recurring, expected);
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_singleEvent_afterRecurrenceEnd_outsideAutorenewGracePeriod() throws Exception {
|
||||
// The domain creation date is 1999-01-05, and the first renewal date is thus 2000-01-05.
|
||||
DateTime testTime = DateTime.parse("2001-02-06T00:00:00Z");
|
||||
clock.setTo(testTime);
|
||||
recurring = persistResource(recurring.asBuilder()
|
||||
// The domain deletion date is 2000-04-05, which is not within the 45 day autorenew grace
|
||||
// period from the renewal date.
|
||||
.setRecurrenceEndTime(DateTime.parse("2000-04-05T00:00:00Z"))
|
||||
.setEventTime(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
clock.setTo(DateTime.parse("2001-02-06T00:00:00Z"));
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring
|
||||
.asBuilder()
|
||||
// The domain deletion date is 2000-04-05, which is not within the 45 day autorenew
|
||||
// grace
|
||||
// period from the renewal date.
|
||||
.setRecurrenceEndTime(DateTime.parse("2000-04-05T00:00:00Z"))
|
||||
.setEventTime(domain.getCreationTime().plusYears(1))
|
||||
.build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.setSyntheticCreationTime(testTime)
|
||||
.build();
|
||||
BillingEvent.OneTime expected =
|
||||
defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2000-02-19T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.build();
|
||||
assertBillingEventsForResource(domain, recurring, expected);
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_billingTimeOnLeapYear() throws Exception {
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring.asBuilder().setEventTime(DateTime.parse("2000-01-15T00:00:00Z")).build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-29T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2000-02-29T00:00:00Z"))
|
||||
.setEventTime(DateTime.parse("2000-01-15T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.build();
|
||||
BillingEvent.OneTime expected =
|
||||
defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2000-02-29T00:00:00Z"))
|
||||
.setEventTime(DateTime.parse("2000-01-15T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.build();
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_expandSingleEvent_billingTimeNotOnLeapYear() throws Exception {
|
||||
DateTime testTime = DateTime.parse("2001-12-01T00:00:00Z");
|
||||
recurring =
|
||||
persistResource(
|
||||
recurring.asBuilder().setEventTime(DateTime.parse("2001-01-15T00:00:00Z")).build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
clock.setTo(testTime);
|
||||
runMapreduce();
|
||||
clock.setTo(DateTime.parse("2001-12-01T00:00:00Z"));
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2001-03-01T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2001-03-01T00:00:00Z"))
|
||||
.setEventTime(DateTime.parse("2001-01-15T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.setSyntheticCreationTime(testTime)
|
||||
.build();
|
||||
BillingEvent.OneTime expected =
|
||||
defaultOneTimeBuilder()
|
||||
.setBillingTime(DateTime.parse("2001-03-01T00:00:00Z"))
|
||||
.setEventTime(DateTime.parse("2001-01-15T00:00:00Z"))
|
||||
.setParent(persistedEntry)
|
||||
.build();
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestSqlOnly
|
||||
void testSuccess_expandMultipleEvents() throws Exception {
|
||||
persistResource(recurring);
|
||||
BillingEvent.Recurring recurring2 = persistResource(recurring.asBuilder()
|
||||
.setEventTime(recurring.getEventTime().plusMonths(3))
|
||||
.setId(3L)
|
||||
.build());
|
||||
BillingEvent.Recurring recurring2 =
|
||||
persistResource(
|
||||
recurring
|
||||
.asBuilder()
|
||||
.setEventTime(recurring.getEventTime().plusMonths(3))
|
||||
.setId(3L)
|
||||
.build());
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
List<DomainHistory> persistedEntries =
|
||||
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertThat(persistedEntries).hasSize(2);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntries.get(0), "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"),
|
||||
domain,
|
||||
persistedEntries.get(0),
|
||||
"TheRegistrar",
|
||||
DateTime.parse("2000-02-19T00:00:00Z"),
|
||||
true);
|
||||
BillingEvent.OneTime expected =
|
||||
defaultOneTimeBuilder()
|
||||
@@ -642,7 +671,10 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.setCancellationMatchingBillingEvent(recurring.createVKey())
|
||||
.build();
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntries.get(1), "TheRegistrar", DateTime.parse("2000-05-20T00:00:00Z"),
|
||||
domain,
|
||||
persistedEntries.get(1),
|
||||
"TheRegistrar",
|
||||
DateTime.parse("2000-05-20T00:00:00Z"),
|
||||
true);
|
||||
BillingEvent.OneTime expected2 =
|
||||
defaultOneTimeBuilder()
|
||||
@@ -652,10 +684,10 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.setCancellationMatchingBillingEvent(recurring2.createVKey())
|
||||
.build();
|
||||
assertBillingEventsForResource(domain, expected, expected2, recurring, recurring2);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_premiumDomain() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
@@ -664,86 +696,87 @@ public class ExpandRecurringBillingEventsActionTest
|
||||
.build());
|
||||
persistResource(recurring);
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
DomainHistory persistedEntry =
|
||||
getOnlyHistoryEntryOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntry, "TheRegistrar", DateTime.parse("2000-02-19T00:00:00Z"), true);
|
||||
BillingEvent.OneTime expected = defaultOneTimeBuilder()
|
||||
.setParent(persistedEntry)
|
||||
.setCost(Money.of(USD, 100))
|
||||
.build();
|
||||
BillingEvent.OneTime expected =
|
||||
defaultOneTimeBuilder().setParent(persistedEntry).setCost(Money.of(USD, 100)).build();
|
||||
assertBillingEventsForResource(domain, expected, recurring);
|
||||
assertCursorAt(beginningOfTest);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_varyingRenewPrices() throws Exception {
|
||||
DateTime testTime = beginningOfTest.plusYears(1);
|
||||
clock.setTo(currentTestTime);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setRenewBillingCostTransitions(
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME, Money.of(USD, 8),
|
||||
DateTime.parse("2000-06-01T00:00:00Z"), Money.of(USD, 10)))
|
||||
START_OF_TIME,
|
||||
Money.of(USD, 8),
|
||||
DateTime.parse("2000-06-01T00:00:00Z"),
|
||||
Money.of(USD, 10)))
|
||||
.build());
|
||||
clock.setTo(testTime);
|
||||
clock.setTo(DateTime.parse("2001-10-02T00:00:00Z"));
|
||||
persistResource(recurring);
|
||||
action.cursorTimeParam = Optional.of(START_OF_TIME);
|
||||
runMapreduce();
|
||||
runAction();
|
||||
List<DomainHistory> persistedEntries =
|
||||
getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW, DomainHistory.class);
|
||||
assertThat(persistedEntries).hasSize(2);
|
||||
DateTime eventDate = DateTime.parse("2000-01-05T00:00:00Z");
|
||||
DateTime billingDate = DateTime.parse("2000-02-19T00:00:00Z");
|
||||
assertHistoryEntryMatches(domain, persistedEntries.get(0), "TheRegistrar", billingDate, true);
|
||||
BillingEvent.OneTime cheaper = defaultOneTimeBuilder()
|
||||
.setBillingTime(billingDate)
|
||||
.setEventTime(eventDate)
|
||||
.setParent(persistedEntries.get(0))
|
||||
.setCost(Money.of(USD, 8))
|
||||
.setSyntheticCreationTime(testTime)
|
||||
.build();
|
||||
BillingEvent.OneTime cheaper =
|
||||
defaultOneTimeBuilder()
|
||||
.setBillingTime(billingDate)
|
||||
.setEventTime(eventDate)
|
||||
.setParent(persistedEntries.get(0))
|
||||
.setCost(Money.of(USD, 8))
|
||||
.build();
|
||||
assertHistoryEntryMatches(
|
||||
domain, persistedEntries.get(1), "TheRegistrar", billingDate.plusYears(1), true);
|
||||
BillingEvent.OneTime expensive = cheaper.asBuilder()
|
||||
.setCost(Money.of(USD, 10))
|
||||
.setBillingTime(billingDate.plusYears(1))
|
||||
.setEventTime(eventDate.plusYears(1))
|
||||
.setParent(persistedEntries.get(1))
|
||||
.build();
|
||||
BillingEvent.OneTime expensive =
|
||||
cheaper
|
||||
.asBuilder()
|
||||
.setCost(Money.of(USD, 10))
|
||||
.setBillingTime(billingDate.plusYears(1))
|
||||
.setEventTime(eventDate.plusYears(1))
|
||||
.setParent(persistedEntries.get(1))
|
||||
.build();
|
||||
assertBillingEventsForResource(domain, recurring, cheaper, expensive);
|
||||
assertCursorAt(testTime);
|
||||
assertCursorAt(currentTestTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_cursorAfterExecutionTime() {
|
||||
action.cursorTimeParam = Optional.of(clock.nowUtc().plusYears(1));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(IllegalArgumentException.class, this::runMapreduce);
|
||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, this::runAction);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.contains("Cursor time must be earlier than execution time.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_cursorAtExecutionTime() {
|
||||
// The clock advances one milli on runMapreduce.
|
||||
action.cursorTimeParam = Optional.of(clock.nowUtc().plusMillis(1));
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(IllegalArgumentException.class, this::runMapreduce);
|
||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, this::runAction);
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.contains("Cursor time must be earlier than execution time.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyOnly
|
||||
void testFailure_mapperException_doesNotMoveCursor() throws Exception {
|
||||
saveCursor(START_OF_TIME); // Need a saved cursor to verify that it didn't move.
|
||||
clock.advanceOneMilli();
|
||||
// Set target to a TLD that doesn't exist.
|
||||
recurring = persistResource(recurring.asBuilder().setTargetId("domain.junk").build());
|
||||
runMapreduce();
|
||||
runAction();
|
||||
// No new history entries should be generated
|
||||
assertThat(getHistoryEntriesOfType(domain, DOMAIN_AUTORENEW)).isEmpty();
|
||||
assertBillingEvents(recurring); // only the bogus one in Datastore
|
||||
|
||||
Reference in New Issue
Block a user