Delete hosts synchronously when using SQL (#1141)

Also put some common logic in helper funcions in ContactDeleteFlowTest
to reduce clutter.
This commit is contained in:
Lai Jiang 2021-05-10 10:22:01 -04:00 committed by GitHub
parent afbb36f68c
commit 6115c7eb21
10 changed files with 268 additions and 218 deletions

View file

@ -32,6 +32,7 @@ import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppinput.ResourceCommand.SingleResourceCommand; import google.registry.model.eppinput.ResourceCommand.SingleResourceCommand;
import google.registry.model.eppoutput.EppResponse; import google.registry.model.eppoutput.EppResponse;
import google.registry.model.eppoutput.Result; import google.registry.model.eppoutput.Result;
import google.registry.model.host.HostHistory;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.util.Optional; import java.util.Optional;
@ -233,11 +234,11 @@ public class FlowModule {
.setClientId(clientId); .setClientId(clientId);
Optional<MetadataExtension> metadataExtension = Optional<MetadataExtension> metadataExtension =
eppInput.getSingleExtension(MetadataExtension.class); eppInput.getSingleExtension(MetadataExtension.class);
if (metadataExtension.isPresent()) { metadataExtension.ifPresent(
historyBuilder extension ->
.setReason(metadataExtension.get().getReason()) historyBuilder
.setRequestedByRegistrar(metadataExtension.get().getRequestedByRegistrar()); .setReason(extension.getReason())
} .setRequestedByRegistrar(extension.getRequestedByRegistrar()));
return historyBuilder; return historyBuilder;
} }
@ -253,6 +254,11 @@ public class FlowModule {
return new DomainHistory.Builder().copyFrom(historyEntryBuilder); return new DomainHistory.Builder().copyFrom(historyEntryBuilder);
} }
@Provides
static HostHistory.Builder provideHostHistoryBuilder(HistoryEntry.Builder historyEntryBuilder) {
return new HostHistory.Builder().copyFrom(historyEntryBuilder);
}
/** /**
* Provides a partially filled in {@link EppResponse} builder. * Provides a partially filled in {@link EppResponse} builder.
* *
@ -263,7 +269,7 @@ public class FlowModule {
static EppResponse.Builder provideEppResponseBuilder(Trid trid) { static EppResponse.Builder provideEppResponseBuilder(Trid trid) {
return new EppResponse.Builder() return new EppResponse.Builder()
.setTrid(trid) .setTrid(trid)
.setResultFromCode(Result.Code.SUCCESS); // Default to success. .setResultFromCode(Result.Code.SUCCESS); // Default to success.
} }
@Provides @Provides

View file

@ -20,12 +20,13 @@ import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses; import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership; import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.host.HostFlowUtils.validateHostName; import static google.registry.flows.host.HostFlowUtils.validateHostName;
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING; import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.batch.AsyncTaskEnqueuer; import google.registry.batch.AsyncTaskEnqueuer;
import google.registry.dns.DnsQueue;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager; import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.ClientId; import google.registry.flows.FlowModule.ClientId;
@ -39,8 +40,11 @@ import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid; import google.registry.model.eppcommon.Trid;
import google.registry.model.eppoutput.EppResponse; import google.registry.model.eppoutput.EppResponse;
import google.registry.model.eppoutput.Result;
import google.registry.model.host.HostHistory;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import javax.inject.Inject; import javax.inject.Inject;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -71,12 +75,14 @@ public final class HostDeleteFlow implements TransactionalFlow {
StatusValue.PENDING_DELETE, StatusValue.PENDING_DELETE,
StatusValue.SERVER_DELETE_PROHIBITED); StatusValue.SERVER_DELETE_PROHIBITED);
private static final DnsQueue dnsQueue = DnsQueue.create();
@Inject ExtensionManager extensionManager; @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId; @Inject @ClientId String clientId;
@Inject @TargetId String targetId; @Inject @TargetId String targetId;
@Inject Trid trid; @Inject Trid trid;
@Inject @Superuser boolean isSuperuser; @Inject @Superuser boolean isSuperuser;
@Inject HistoryEntry.Builder historyBuilder; @Inject HostHistory.Builder historyBuilder;
@Inject AsyncTaskEnqueuer asyncTaskEnqueuer; @Inject AsyncTaskEnqueuer asyncTaskEnqueuer;
@Inject EppResponse.Builder responseBuilder; @Inject EppResponse.Builder responseBuilder;
@ -102,16 +108,31 @@ public final class HostDeleteFlow implements TransactionalFlow {
: existingHost; : existingHost;
verifyResourceOwnership(clientId, owningResource); verifyResourceOwnership(clientId, owningResource);
} }
asyncTaskEnqueuer.enqueueAsyncDelete( HistoryEntry.Type historyEntryType;
existingHost, tm().getTransactionTime(), clientId, trid, isSuperuser); Result.Code resultCode;
HostResource newHost = HostResource newHost;
existingHost.asBuilder().addStatusValue(StatusValue.PENDING_DELETE).build(); if (tm().isOfy()) {
historyBuilder asyncTaskEnqueuer.enqueueAsyncDelete(
.setType(HistoryEntry.Type.HOST_PENDING_DELETE) existingHost, tm().getTransactionTime(), clientId, trid, isSuperuser);
.setModificationTime(now) newHost = existingHost.asBuilder().addStatusValue(StatusValue.PENDING_DELETE).build();
.setParent(Key.create(existingHost)); historyEntryType = Type.HOST_PENDING_DELETE;
tm().insert(historyBuilder.build().toChildHistoryEntity()); resultCode = SUCCESS_WITH_ACTION_PENDING;
} else {
newHost = existingHost.asBuilder().setStatusValues(null).setDeletionTime(now).build();
if (existingHost.isSubordinate()) {
dnsQueue.addHostRefreshTask(existingHost.getHostName());
tm().update(
tm().loadByKey(existingHost.getSuperordinateDomain())
.asBuilder()
.removeSubordinateHost(existingHost.getHostName())
.build());
}
historyEntryType = Type.HOST_DELETE;
resultCode = SUCCESS;
}
historyBuilder.setType(historyEntryType).setModificationTime(now).setHostBase(newHost);
tm().insert(historyBuilder.build());
tm().update(newHost); tm().update(newHost);
return responseBuilder.setResultFromCode(SUCCESS_WITH_ACTION_PENDING).build(); return responseBuilder.setResultFromCode(resultCode).build();
} }
} }

View file

@ -65,22 +65,22 @@ class EppLifecycleContactTest extends EppTestCase {
.hasCommandName("ContactInfo") .hasCommandName("ContactInfo")
.and() .and()
.hasStatus(SUCCESS); .hasStatus(SUCCESS);
Result.Code resultCode; Result.Code deleteResultCode;
if (tm().isOfy()) { if (tm().isOfy()) {
assertThatCommand("contact_delete_sh8013.xml") assertThatCommand("contact_delete_sh8013.xml")
.hasResponse("contact_delete_response_sh8013_pending.xml"); .hasResponse("contact_delete_response_sh8013_pending.xml");
resultCode = SUCCESS_WITH_ACTION_PENDING; deleteResultCode = SUCCESS_WITH_ACTION_PENDING;
} else { } else {
assertThatCommand("contact_delete_sh8013.xml") assertThatCommand("contact_delete_sh8013.xml")
.hasResponse("contact_delete_response_sh8013.xml"); .hasResponse("contact_delete_response_sh8013.xml");
resultCode = SUCCESS; deleteResultCode = SUCCESS;
} }
assertThat(getRecordedEppMetric()) assertThat(getRecordedEppMetric())
.hasClientId("NewRegistrar") .hasClientId("NewRegistrar")
.and() .and()
.hasCommandName("ContactDelete") .hasCommandName("ContactDelete")
.and() .and()
.hasStatus(resultCode); .hasStatus(deleteResultCode);
assertThatLogoutSucceeds(); assertThatLogoutSucceeds();
} }

View file

@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey; import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.eppoutput.Result.Code.SUCCESS; import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING; import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.createTld; import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.createTlds; import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.EppMetricSubject.assertThat; import static google.registry.testing.EppMetricSubject.assertThat;
@ -25,6 +26,7 @@ import static google.registry.testing.HostResourceSubject.assertAboutHosts;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.eppoutput.Result;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.testing.AppEngineExtension; import google.registry.testing.AppEngineExtension;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
@ -80,15 +82,24 @@ class EppLifecycleHostTest extends EppTestCase {
.hasCommandName("HostInfo") .hasCommandName("HostInfo")
.and() .and()
.hasStatus(SUCCESS); .hasStatus(SUCCESS);
assertThatCommand("host_delete.xml", ImmutableMap.of("HOSTNAME", "ns1.example.tld")) Result.Code deleteResultCode;
.atTime("2000-06-02T00:03:00Z") if (tm().isOfy()) {
.hasResponse("generic_success_action_pending_response.xml"); assertThatCommand("host_delete.xml", ImmutableMap.of("HOSTNAME", "ns1.example.tld"))
.atTime("2000-06-02T00:03:00Z")
.hasResponse("generic_success_action_pending_response.xml");
deleteResultCode = SUCCESS_WITH_ACTION_PENDING;
} else {
assertThatCommand("host_delete.xml", ImmutableMap.of("HOSTNAME", "ns1.example.tld"))
.atTime("2000-06-02T00:03:00Z")
.hasResponse("generic_success_response.xml");
deleteResultCode = SUCCESS;
}
assertThat(getRecordedEppMetric()) assertThat(getRecordedEppMetric())
.hasClientId("NewRegistrar") .hasClientId("NewRegistrar")
.and() .and()
.hasCommandName("HostDelete") .hasCommandName("HostDelete")
.and() .and()
.hasStatus(SUCCESS_WITH_ACTION_PENDING); .hasStatus(deleteResultCode);
assertThatLogoutSucceeds(); assertThatLogoutSucceeds();
} }

View file

@ -17,7 +17,7 @@ package google.registry.flows.contact;
import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.collect.MoreCollectors.onlyElement;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE; import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE;
import static google.registry.model.reporting.HistoryEntry.Type.CONTACT_PENDING_DELETE; import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.ContactResourceSubject.assertAboutContacts; import static google.registry.testing.ContactResourceSubject.assertAboutContacts;
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents; import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
import static google.registry.testing.DatabaseHelper.createTld; import static google.registry.testing.DatabaseHelper.createTld;
@ -46,6 +46,7 @@ import google.registry.model.eppcommon.Trid;
import google.registry.model.poll.PendingActionNotificationResponse; import google.registry.model.poll.PendingActionNotificationResponse;
import google.registry.model.poll.PollMessage; import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.Type; import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferResponse; import google.registry.model.transfer.TransferResponse;
@ -53,7 +54,6 @@ import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import google.registry.testing.TestSqlOnly; import google.registry.testing.TestSqlOnly;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -73,61 +73,28 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
setEppInput("contact_delete.xml"); setEppInput("contact_delete.xml");
} }
@TestOfyOnly @TestOfyAndSql
void testDryRun_ofy() throws Exception { void testDryRun() throws Exception {
persistActiveContact(getUniqueIdFromCommand()); persistActiveContact(getUniqueIdFromCommand());
dryRunFlowAssertResponse(loadFile("contact_delete_response_pending.xml")); if (tm().isOfy()) {
dryRunFlowAssertResponse(loadFile("contact_delete_response_pending.xml"));
} else {
dryRunFlowAssertResponse(loadFile("contact_delete_response.xml"));
}
} }
@TestSqlOnly @TestOfyAndSql
void testDryRun_sql() throws Exception { void testSuccess() throws Exception {
persistActiveContact(getUniqueIdFromCommand());
dryRunFlowAssertResponse(loadFile("contact_delete_response.xml"));
}
@TestOfyOnly
void testSuccess_ofy() throws Exception {
persistActiveContact(getUniqueIdFromCommand()); persistActiveContact(getUniqueIdFromCommand());
clock.advanceOneMilli(); clock.advanceOneMilli();
assertTransactionalFlow(true); assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("contact_delete_response_pending.xml")); if (tm().isOfy()) {
ContactResource deletedContact = reloadResourceByForeignKey(); runFlowAssertResponse(loadFile("contact_delete_response_pending.xml"));
assertAboutContacts().that(deletedContact).hasStatusValue(StatusValue.PENDING_DELETE); assertOfyDeleteSuccess();
assertAsyncDeletionTaskEnqueued( } else {
deletedContact, "TheRegistrar", Trid.create("ABC-12345", "server-trid"), false); runFlowAssertResponse(loadFile("contact_delete_response.xml"));
assertAboutContacts() assertSqlDeleteSuccess();
.that(deletedContact) }
.hasOnlyOneHistoryEntryWhich()
.hasType(Type.CONTACT_PENDING_DELETE);
assertNoBillingEvents();
assertLastHistoryContainsResource(deletedContact);
}
@TestSqlOnly
void testSuccess_sql() throws Exception {
persistActiveContact(getUniqueIdFromCommand());
clock.advanceOneMilli();
assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("contact_delete_response.xml"));
assertThat(reloadResourceByForeignKey()).isNull();
assertAboutContacts()
.that(reloadResourceByForeignKey(clock.nowUtc().minusMillis(1)))
.isNotActiveAt(clock.nowUtc())
.and()
.hasNullLocalizedPostalInfo()
.and()
.hasNullInternationalizedPostalInfo()
.and()
.hasNullEmailAddress()
.and()
.hasNullVoiceNumber()
.and()
.hasNullFaxNumber()
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(Type.CONTACT_DELETE);
assertNoTasksEnqueued(QUEUE_ASYNC_DELETE);
assertNoBillingEvents();
} }
@TestSqlOnly @TestSqlOnly
@ -143,23 +110,8 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
clock.advanceOneMilli(); clock.advanceOneMilli();
assertTransactionalFlow(true); assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("contact_delete_response.xml")); runFlowAssertResponse(loadFile("contact_delete_response.xml"));
assertThat(reloadResourceByForeignKey()).isNull(); assertSqlDeleteSuccess(Type.CONTACT_DELETE, Type.CONTACT_TRANSFER_REQUEST);
ContactResource softDeletedContact = reloadResourceByForeignKey(clock.nowUtc().minusMillis(1)); ContactResource softDeletedContact = reloadResourceByForeignKey(clock.nowUtc().minusMillis(1));
assertAboutContacts()
.that(softDeletedContact)
.isNotActiveAt(clock.nowUtc())
.and()
.hasNullLocalizedPostalInfo()
.and()
.hasNullInternationalizedPostalInfo()
.and()
.hasNullEmailAddress()
.and()
.hasNullVoiceNumber()
.and()
.hasNullFaxNumber()
.and()
.hasOneHistoryEntryEachOfTypes(Type.CONTACT_DELETE, Type.CONTACT_TRANSFER_REQUEST);
assertThat(softDeletedContact.getTransferData()) assertThat(softDeletedContact.getTransferData())
.isEqualTo( .isEqualTo(
oldTransferData oldTransferData
@ -185,54 +137,21 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
assertThat(panData.getTrid()) assertThat(panData.getTrid())
.isEqualTo(Trid.create("transferClient-trid", "transferServer-trid")); .isEqualTo(Trid.create("transferClient-trid", "transferServer-trid"));
assertThat(panData.getActionResult()).isFalse(); assertThat(panData.getActionResult()).isFalse();
assertNoTasksEnqueued(QUEUE_ASYNC_DELETE);
assertNoBillingEvents();
} }
@TestOfyOnly @TestOfyAndSql
void testSuccess_clTridNotSpecified_ofy() throws Exception { void testSuccess_clTridNotSpecified() throws Exception {
setEppInput("contact_delete_no_cltrid.xml"); setEppInput("contact_delete_no_cltrid.xml");
persistActiveContact(getUniqueIdFromCommand()); persistActiveContact(getUniqueIdFromCommand());
clock.advanceOneMilli(); clock.advanceOneMilli();
assertTransactionalFlow(true); assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("contact_delete_response_no_cltrid_pending.xml")); if (tm().isOfy()) {
ContactResource deletedContact = reloadResourceByForeignKey(); runFlowAssertResponse(loadFile("contact_delete_response_no_cltrid_pending.xml"));
assertAboutContacts().that(deletedContact).hasStatusValue(StatusValue.PENDING_DELETE); assertOfyDeleteSuccess("TheRegistrar", null, false);
assertAsyncDeletionTaskEnqueued( } else {
deletedContact, "TheRegistrar", Trid.create(null, "server-trid"), false); runFlowAssertResponse(loadFile("contact_delete_response_no_cltrid.xml"));
assertAboutContacts() assertSqlDeleteSuccess();
.that(deletedContact) }
.hasOnlyOneHistoryEntryWhich()
.hasType(CONTACT_PENDING_DELETE);
assertNoBillingEvents();
}
@TestSqlOnly
void testSuccess_clTridNotSpecified_sql() throws Exception {
setEppInput("contact_delete_no_cltrid.xml");
persistActiveContact(getUniqueIdFromCommand());
clock.advanceOneMilli();
assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("contact_delete_response_no_cltrid.xml"));
assertThat(reloadResourceByForeignKey()).isNull();
assertAboutContacts()
.that(reloadResourceByForeignKey(clock.nowUtc().minusMillis(1)))
.isNotActiveAt(clock.nowUtc())
.and()
.hasNullLocalizedPostalInfo()
.and()
.hasNullInternationalizedPostalInfo()
.and()
.hasNullEmailAddress()
.and()
.hasNullVoiceNumber()
.and()
.hasNullFaxNumber()
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(Type.CONTACT_DELETE);
assertNoTasksEnqueued(QUEUE_ASYNC_DELETE);
assertNoBillingEvents();
} }
@TestOfyAndSql @TestOfyAndSql
@ -290,50 +209,22 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyOnly @TestOfyAndSql
void testSuccess_superuserUnauthorizedClient_ofy() throws Exception { void testSuccess_superuserUnauthorizedClient() throws Exception {
sessionMetadata.setClientId("NewRegistrar"); sessionMetadata.setClientId("NewRegistrar");
persistActiveContact(getUniqueIdFromCommand()); persistActiveContact(getUniqueIdFromCommand());
clock.advanceOneMilli(); clock.advanceOneMilli();
runFlowAssertResponse( if (tm().isOfy()) {
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("contact_delete_response_pending.xml")); runFlowAssertResponse(
ContactResource deletedContact = reloadResourceByForeignKey(); CommitMode.LIVE,
assertAboutContacts().that(deletedContact).hasStatusValue(StatusValue.PENDING_DELETE); UserPrivileges.SUPERUSER,
assertAsyncDeletionTaskEnqueued( loadFile("contact_delete_response_pending.xml"));
deletedContact, "NewRegistrar", Trid.create("ABC-12345", "server-trid"), true); assertOfyDeleteSuccess("NewRegistrar", "ABC-12345", true);
assertAboutContacts() } else {
.that(deletedContact) runFlowAssertResponse(
.hasOnlyOneHistoryEntryWhich() CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("contact_delete_response.xml"));
.hasType(CONTACT_PENDING_DELETE); assertSqlDeleteSuccess();
assertNoBillingEvents(); }
}
@TestSqlOnly
void testSuccess_superuserUnauthorizedClient_sql() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
persistActiveContact(getUniqueIdFromCommand());
clock.advanceOneMilli();
runFlowAssertResponse(
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("contact_delete_response.xml"));
assertThat(reloadResourceByForeignKey()).isNull();
assertAboutContacts()
.that(reloadResourceByForeignKey(clock.nowUtc().minusMillis(1)))
.isNotActiveAt(clock.nowUtc())
.and()
.hasNullLocalizedPostalInfo()
.and()
.hasNullInternationalizedPostalInfo()
.and()
.hasNullEmailAddress()
.and()
.hasNullVoiceNumber()
.and()
.hasNullFaxNumber()
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(Type.CONTACT_DELETE);
assertNoTasksEnqueued(QUEUE_ASYNC_DELETE);
assertNoBillingEvents();
} }
@TestOfyAndSql @TestOfyAndSql
@ -359,4 +250,50 @@ class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, Cont
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-cont-delete"); assertIcannReportingActivityFieldLogged("srs-cont-delete");
} }
private void assertOfyDeleteSuccess(String clientId, String clientTrid, boolean isSuperuser)
throws Exception {
ContactResource deletedContact = reloadResourceByForeignKey();
assertAsyncDeletionTaskEnqueued(
deletedContact, clientId, Trid.create(clientTrid, "server-trid"), isSuperuser);
assertAboutContacts()
.that(deletedContact)
.hasStatusValue(StatusValue.PENDING_DELETE)
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(Type.CONTACT_PENDING_DELETE);
assertNoBillingEvents();
assertLastHistoryContainsResource(deletedContact);
}
private void assertOfyDeleteSuccess() throws Exception {
assertOfyDeleteSuccess("TheRegistrar", "ABC-12345", false);
}
private void assertSqlDeleteSuccess(HistoryEntry.Type... historyEntryTypes) throws Exception {
assertThat(reloadResourceByForeignKey()).isNull();
assertAboutContacts()
.that(reloadResourceByForeignKey(clock.nowUtc().minusMillis(1)))
.isNotActiveAt(clock.nowUtc())
.and()
.hasNullLocalizedPostalInfo()
.and()
.hasNullInternationalizedPostalInfo()
.and()
.hasNullEmailAddress()
.and()
.hasNullVoiceNumber()
.and()
.hasNullFaxNumber()
.and()
.hasExactlyStatusValues(StatusValue.OK)
.and()
.hasOneHistoryEntryEachOfTypes(historyEntryTypes);
assertNoTasksEnqueued(QUEUE_ASYNC_DELETE);
assertNoBillingEvents();
}
private void assertSqlDeleteSuccess() throws Exception {
assertSqlDeleteSuccess(Type.CONTACT_DELETE);
}
} }

View file

@ -15,8 +15,11 @@
package google.registry.flows.host; package google.registry.flows.host;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents; import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
import static google.registry.testing.DatabaseHelper.createTld; import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadByKey;
import static google.registry.testing.DatabaseHelper.newDomainBase; import static google.registry.testing.DatabaseHelper.newDomainBase;
import static google.registry.testing.DatabaseHelper.newHostResource; import static google.registry.testing.DatabaseHelper.newHostResource;
import static google.registry.testing.DatabaseHelper.persistActiveHost; import static google.registry.testing.DatabaseHelper.persistActiveHost;
@ -24,7 +27,9 @@ import static google.registry.testing.DatabaseHelper.persistDeletedHost;
import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
import static google.registry.testing.HostResourceSubject.assertAboutHosts; import static google.registry.testing.HostResourceSubject.assertAboutHosts;
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued; import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
import static google.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -43,7 +48,7 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid; import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.model.transfer.DomainTransferData; import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus; import google.registry.model.transfer.TransferStatus;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
@ -70,7 +75,11 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, HostResour
@TestOfyAndSql @TestOfyAndSql
void testDryRun() throws Exception { void testDryRun() throws Exception {
persistActiveHost("ns1.example.tld"); persistActiveHost("ns1.example.tld");
dryRunFlowAssertResponse(loadFile("host_delete_response.xml")); if (tm().isOfy()) {
dryRunFlowAssertResponse(loadFile("host_delete_response_pending.xml"));
} else {
dryRunFlowAssertResponse(loadFile("host_delete_response.xml"));
}
} }
@TestOfyAndSql @TestOfyAndSql
@ -78,17 +87,13 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, HostResour
persistActiveHost("ns1.example.tld"); persistActiveHost("ns1.example.tld");
clock.advanceOneMilli(); clock.advanceOneMilli();
assertTransactionalFlow(true); assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("host_delete_response.xml")); if (tm().isOfy()) {
HostResource deletedHost = reloadResourceByForeignKey(); runFlowAssertResponse(loadFile("host_delete_response_pending.xml"));
assertAboutHosts().that(deletedHost).hasStatusValue(StatusValue.PENDING_DELETE); assertOfyDeleteSuccess();
assertAsyncDeletionTaskEnqueued( } else {
deletedHost, "TheRegistrar", Trid.create("ABC-12345", "server-trid"), false); runFlowAssertResponse(loadFile("host_delete_response.xml"));
assertAboutHosts() assertSqlDeleteSuccess();
.that(deletedHost) }
.hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_PENDING_DELETE);
assertNoBillingEvents();
assertNoDnsTasksEnqueued();
} }
@TestOfyAndSql @TestOfyAndSql
@ -97,17 +102,13 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, HostResour
persistActiveHost("ns1.example.tld"); persistActiveHost("ns1.example.tld");
clock.advanceOneMilli(); clock.advanceOneMilli();
assertTransactionalFlow(true); assertTransactionalFlow(true);
runFlowAssertResponse(loadFile("host_delete_response_no_cltrid.xml")); if (tm().isOfy()) {
HostResource deletedHost = reloadResourceByForeignKey(); runFlowAssertResponse(loadFile("host_delete_response_no_cltrid_pending.xml"));
assertAboutHosts().that(deletedHost).hasStatusValue(StatusValue.PENDING_DELETE); assertOfyDeleteSuccess("TheRegistrar", null, false);
assertAsyncDeletionTaskEnqueued( } else {
deletedHost, "TheRegistrar", Trid.create(null, "server-trid"), false); runFlowAssertResponse(loadFile("host_delete_response_no_cltrid.xml"));
assertAboutHosts() assertSqlDeleteSuccess();
.that(deletedHost) }
.hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_PENDING_DELETE);
assertNoBillingEvents();
assertNoDnsTasksEnqueued();
} }
@TestOfyAndSql @TestOfyAndSql
@ -166,18 +167,15 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, HostResour
sessionMetadata.setClientId("NewRegistrar"); sessionMetadata.setClientId("NewRegistrar");
persistActiveHost("ns1.example.tld"); persistActiveHost("ns1.example.tld");
clock.advanceOneMilli(); clock.advanceOneMilli();
runFlowAssertResponse( if (tm().isOfy()) {
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("host_delete_response.xml")); runFlowAssertResponse(
HostResource deletedHost = reloadResourceByForeignKey(); CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("host_delete_response_pending.xml"));
assertAboutHosts().that(deletedHost).hasStatusValue(StatusValue.PENDING_DELETE); assertOfyDeleteSuccess("NewRegistrar", "ABC-12345", true);
assertAsyncDeletionTaskEnqueued( } else {
deletedHost, "NewRegistrar", Trid.create("ABC-12345", "server-trid"), true); runFlowAssertResponse(
assertAboutHosts() CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("host_delete_response.xml"));
.that(deletedHost) assertSqlDeleteSuccess();
.hasOnlyOneHistoryEntryWhich() }
.hasType(HistoryEntry.Type.HOST_PENDING_DELETE);
assertNoBillingEvents();
assertNoDnsTasksEnqueued();
} }
@TestOfyAndSql @TestOfyAndSql
@ -197,7 +195,13 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, HostResour
.setSuperordinateDomain(domain.createVKey()) .setSuperordinateDomain(domain.createVKey())
.build()); .build());
clock.advanceOneMilli(); clock.advanceOneMilli();
runFlowAssertResponse(loadFile("host_delete_response.xml")); if (tm().isOfy()) {
runFlowAssertResponse(loadFile("host_delete_response_pending.xml"));
assertOfyDeleteSuccess();
} else {
runFlowAssertResponse(loadFile("host_delete_response.xml"));
assertSqlDeleteSuccess(true);
}
} }
@TestOfyAndSql @TestOfyAndSql
@ -250,7 +254,13 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, HostResour
.setSuperordinateDomain(domain.createVKey()) .setSuperordinateDomain(domain.createVKey())
.build()); .build());
clock.advanceOneMilli(); clock.advanceOneMilli();
runFlowAssertResponse(loadFile("host_delete_response.xml")); if (tm().isOfy()) {
runFlowAssertResponse(loadFile("host_delete_response_pending.xml"));
assertOfyDeleteSuccess("NewRegistrar", "ABC-12345", false);
} else {
runFlowAssertResponse(loadFile("host_delete_response.xml"));
assertSqlDeleteSuccess(true);
}
} }
@TestOfyAndSql @TestOfyAndSql
@ -327,4 +337,48 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, HostResour
runFlow(); runFlow();
assertIcannReportingActivityFieldLogged("srs-host-delete"); assertIcannReportingActivityFieldLogged("srs-host-delete");
} }
private void assertOfyDeleteSuccess(String clientId, String clientTrid, boolean isSuperuser)
throws Exception {
HostResource deletedHost = reloadResourceByForeignKey();
assertAsyncDeletionTaskEnqueued(
deletedHost, clientId, Trid.create(clientTrid, "server-trid"), isSuperuser);
assertAboutHosts()
.that(deletedHost)
.hasStatusValue(StatusValue.PENDING_DELETE)
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(Type.HOST_PENDING_DELETE);
assertNoBillingEvents();
assertNoDnsTasksEnqueued();
}
private void assertOfyDeleteSuccess() throws Exception {
assertOfyDeleteSuccess("TheRegistrar", "ABC-12345", false);
}
private void assertSqlDeleteSuccess(boolean isSubordinate) throws Exception {
assertThat(reloadResourceByForeignKey()).isNull();
HostResource deletedHost = reloadResourceByForeignKey(clock.nowUtc().minusMillis(1));
assertAboutHosts()
.that(deletedHost)
.isNotActiveAt(clock.nowUtc())
.and()
.hasExactlyStatusValues(StatusValue.OK)
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(Type.HOST_DELETE);
assertNoBillingEvents();
if (isSubordinate) {
assertDnsTasksEnqueued(deletedHost.getHostName());
assertThat(loadByKey(deletedHost.getSuperordinateDomain()).getSubordinateHosts()).isEmpty();
} else {
assertNoDnsTasksEnqueued();
}
assertNoTasksEnqueued(QUEUE_ASYNC_DELETE);
}
private void assertSqlDeleteSuccess() throws Exception {
assertSqlDeleteSuccess(false);
}
} }

View file

@ -1,7 +1,7 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"> <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response> <response>
<result code="1001"> <result code="1000">
<msg>Command completed successfully; action pending</msg> <msg>Command completed successfully</msg>
</result> </result>
<trID> <trID>
<clTRID>ABC-12345</clTRID> <clTRID>ABC-12345</clTRID>

View file

@ -1,7 +1,7 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"> <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response> <response>
<result code="1001"> <result code="1000">
<msg>Command completed successfully; action pending</msg> <msg>Command completed successfully</msg>
</result> </result>
<trID> <trID>
<svTRID>server-trid</svTRID> <svTRID>server-trid</svTRID>

View file

@ -0,0 +1,10 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1001">
<msg>Command completed successfully; action pending</msg>
</result>
<trID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,11 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1001">
<msg>Command completed successfully; action pending</msg>
</result>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>