Better handle deletion of prober domains

This implements a two-part deletion process for prober domains that were
not deleted properly by the prober (which is usually caused by a transient
network failure). The first time the mapreduce is run, such domains are
soft-deleted, so that their DNS entries can be removed correctly, and then
they are hard-deleted in the subsequent run.

Currently, all domains are hard-deleted the first time this mapreduce
runs, even if they were never soft-deleted correctly, which means that
their published DNS entries won't be correctly handled.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=165612973
This commit is contained in:
mcilwain 2017-09-07 12:30:38 -04:00 committed by Ben McIlwain
parent b0c254dc65
commit 46f175e078
2 changed files with 167 additions and 10 deletions

View file

@ -15,13 +15,21 @@
package google.registry.batch;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assert_;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.newDomainResource;
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
import static google.registry.testing.DatastoreHelper.persistActiveHost;
import static google.registry.testing.DatastoreHelper.persistDeletedDomain;
import static google.registry.testing.DatastoreHelper.persistDomainAsDeleted;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.DatastoreHelper.persistSimpleResource;
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.time.DateTimeZone.UTC;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
@ -75,6 +83,7 @@ public class DeleteProberDataActionTest extends MapreduceTestCase<DeleteProberDa
action.mrRunner = makeDefaultRunner();
action.response = new FakeResponse();
action.isDryRun = false;
action.registryAdminClientId = "TheRegistrar";
}
private void runMapreduce() throws Exception {
@ -107,14 +116,90 @@ public class DeleteProberDataActionTest extends MapreduceTestCase<DeleteProberDa
}
@Test
public void testSuccess_dryRunDoesntDeleteData() throws Exception {
public void testDryRun_doesntDeleteData() throws Exception {
Set<ImmutableObject> tldEntities = persistLotsOfDomains("tld");
Set<ImmutableObject> oaEntities = persistLotsOfDomains("oa-canary.test");
action.isDryRun = true;
runMapreduce();
assertNotDeleted(tldEntities);
assertNotDeleted(oaEntities);
}
@Test
public void testSuccess_activeDomain_isSoftDeleted() throws Exception {
DomainResource domain = persistResource(
newDomainResource("blah.ib-any.test")
.asBuilder()
.setCreationTimeForTest(DateTime.now(UTC).minusYears(1))
.build());
runMapreduce();
DateTime timeAfterDeletion = DateTime.now(UTC);
assertThat(loadByForeignKey(DomainResource.class, "blah.ib-any.test", timeAfterDeletion))
.isNull();
assertThat(ofy().load().entity(domain).now().getDeletionTime()).isLessThan(timeAfterDeletion);
assertDnsTasksEnqueued("blah.ib-any.test");
}
@Test
public void test_recentlyCreatedDomain_isntDeletedYet() throws Exception {
persistResource(
newDomainResource("blah.ib-any.test")
.asBuilder()
.setCreationTimeForTest(DateTime.now(UTC).minusSeconds(1))
.build());
runMapreduce();
DomainResource domain =
loadByForeignKey(DomainResource.class, "blah.ib-any.test", DateTime.now(UTC));
assertThat(domain).isNotNull();
assertThat(domain.getDeletionTime()).isEqualTo(END_OF_TIME);
}
@Test
public void testDryRun_doesntSoftDeleteData() throws Exception {
DomainResource domain = persistResource(
newDomainResource("blah.ib-any.test")
.asBuilder()
.setCreationTimeForTest(DateTime.now(UTC).minusYears(1))
.build());
action.isDryRun = true;
runMapreduce();
assertThat(ofy().load().entity(domain).now().getDeletionTime()).isEqualTo(END_OF_TIME);
}
@Test
public void test_domainWithSubordinateHosts_isSkipped() throws Exception {
persistActiveHost("ns1.blah.ib-any.test");
DomainResource nakedDomain =
persistDeletedDomain("todelete.ib-any.test", DateTime.now(UTC).minusYears(1));
DomainResource domainWithSubord =
persistDomainAsDeleted(
newDomainResource("blah.ib-any.test")
.asBuilder()
.setSubordinateHosts(ImmutableSet.of("ns1.blah.ib-any.test"))
.build(),
DateTime.now(UTC).minusYears(1));
runMapreduce();
assertThat(ofy().load().entity(domainWithSubord).now()).isNotNull();
assertThat(ofy().load().entity(nakedDomain).now()).isNull();
}
@Test
public void testFailure_registryAdminClientId_isRequiredForSoftDeletion() throws Exception {
persistResource(
newDomainResource("blah.ib-any.test")
.asBuilder()
.setCreationTimeForTest(DateTime.now(UTC).minusYears(1))
.build());
action.registryAdminClientId = null;
try {
runMapreduce();
} catch (IllegalStateException e) {
assertThat(e).hasMessageThat().contains("Registry admin client ID must be configured");
return;
}
assert_().fail("Expected IllegalStateException");
}
/**
* Persists and returns a domain and a descendant history entry, billing event, and poll message,
* along with the ForeignKeyIndex and EppResourceIndex.