From 00dab551d7f4debb3ae70fecfc4ef4b338303ec9 Mon Sep 17 00:00:00 2001 From: ctingue Date: Thu, 5 Jan 2017 12:04:59 -0800 Subject: [PATCH] Fix deleted domain bug in recurring billing expansion Currently, the recurring billing expansion chokes when looking for existing OneTime events for domains that are deleted or transferred at the MR execution time. To fix this, change the FKI query to look for a key at either execution time or recurrence end time, whichever is earliest. (This one is distinct from [] in that this bug occurs when domains are [] deleted.) ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=143693153 --- .../ExpandRecurringBillingEventsAction.java | 9 +++-- ...xpandRecurringBillingEventsActionTest.java | 36 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/java/google/registry/batch/ExpandRecurringBillingEventsAction.java b/java/google/registry/batch/ExpandRecurringBillingEventsAction.java index 44a0a4ec8..f5dc06c0e 100644 --- a/java/google/registry/batch/ExpandRecurringBillingEventsAction.java +++ b/java/google/registry/batch/ExpandRecurringBillingEventsAction.java @@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.Sets.difference; import static google.registry.mapreduce.MapreduceRunner.PARAM_DRY_RUN; import static google.registry.mapreduce.inputs.EppResourceInputs.createChildEntityInput; -import static google.registry.model.EppResourceUtils.loadByForeignKey; import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost; @@ -167,8 +166,14 @@ public class ExpandRecurringBillingEventsAction implements Runnable { Iterable oneTimesForDomain = ofy().load() .type(OneTime.class) + .ancestor(recurring.getParentKey().getParent()); + /* .ancestor(loadByForeignKey( - DomainResource.class, recurring.getTargetId(), executeTime)); + DomainResource.class, + recurring.getTargetId(), + // Whether or not a domain currently exists, it always exists one millisecond + // before the recurrence end time. + recurring.getRecurrenceEndTime().minusMillis(1))); */ // Determine the billing times that already have OneTime events persisted. ImmutableSet existingBillingTimes = diff --git a/javatests/google/registry/batch/ExpandRecurringBillingEventsActionTest.java b/javatests/google/registry/batch/ExpandRecurringBillingEventsActionTest.java index 92ac3995f..4d454e008 100644 --- a/javatests/google/registry/batch/ExpandRecurringBillingEventsActionTest.java +++ b/javatests/google/registry/batch/ExpandRecurringBillingEventsActionTest.java @@ -21,6 +21,7 @@ import static google.registry.testing.DatastoreHelper.assertBillingEvents; import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.persistActiveDomain; +import static google.registry.testing.DatastoreHelper.persistDeletedDomain; import static google.registry.testing.DatastoreHelper.persistPremiumList; import static google.registry.testing.DatastoreHelper.persistResource; import static google.registry.util.DateTimeUtils.END_OF_TIME; @@ -140,6 +141,41 @@ public class ExpandRecurringBillingEventsActionTest assertCursorAt(beginningOfTest); } + @Test + public void testSuccess_expandSingleEvent_deletedDomain() throws Exception { + DateTime deletionTime = DateTime.parse("2000-08-01T00:00:00Z"); + DomainResource deletedDomain = persistDeletedDomain("deleted.tld", deletionTime); + historyEntry = persistResource(new HistoryEntry.Builder().setParent(deletedDomain).build()); + recurring = persistResource(new BillingEvent.Recurring.Builder() + .setParent(historyEntry) + .setClientId(deletedDomain.getCreationClientId()) + .setEventTime(DateTime.parse("2000-01-05T00:00:00Z")) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setId(2L) + .setReason(Reason.RENEW) + .setRecurrenceEndTime(deletionTime) + .setTargetId(deletedDomain.getFullyQualifiedDomainName()) + .build()); + action.cursorTimeParam = Optional.of(START_OF_TIME); + runMapreduce(); + BillingEvent.OneTime expected = new BillingEvent.OneTime.Builder() + // 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) + .setPeriodYears(1) + .setReason(Reason.RENEW) + .setSyntheticCreationTime(beginningOfTest) + .setCancellationMatchingBillingEvent(Key.create(recurring)) + .setTargetId(deletedDomain.getFullyQualifiedDomainName()) + .build(); + assertBillingEventsForResource(deletedDomain, expected, recurring); + assertCursorAt(beginningOfTest); + } + @Test public void testSuccess_expandSingleEvent_idempotentForDuplicateRuns() throws Exception { persistResource(recurring);