mirror of
https://github.com/google/nomulus.git
synced 2025-07-08 20:23:24 +02:00
Convert poll-message-related classes to use SQL as well (#1050)
* Convert poll-message-related classes to use SQL as well Two relatively complex parts. The first is that we needed a small refactor on the AckPollMessagesCommand because we could theoretically be acking more poll messages than the Datastore transaction size boundary. This means that the normal flow of "gather the poll messages from the DB into one collection, then act on it" needs to be changed to a more functional flow. The second is that acking the poll message (deleting it in most cases) reduces the number of remaining poll messages in SQL but not in Datastore, since in Datastore the deletion does not take effect until after the transaction is over.
This commit is contained in:
parent
75e74f013d
commit
7c3ef52026
12 changed files with 322 additions and 166 deletions
|
@ -32,14 +32,16 @@ import google.registry.flows.poll.PollAckFlow.NotAuthorizedToAckMessageException
|
|||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.ReplayExtension;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link PollAckFlow}. */
|
||||
@DualDatabaseTest
|
||||
class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
||||
|
||||
@Order(value = Order.DEFAULT - 2)
|
||||
|
@ -89,13 +91,13 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testDryRun() throws Exception {
|
||||
persistOneTimePollMessage(MESSAGE_ID);
|
||||
dryRunFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_contactPollMessage() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "2-2-ROID-4-3-2011"));
|
||||
persistResource(
|
||||
|
@ -110,7 +112,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_contactPollMessage_withIncorrectYearField() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "2-2-ROID-4-3-1999"));
|
||||
persistResource(
|
||||
|
@ -125,14 +127,14 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
assertThrows(MessageDoesNotExistException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_messageOnContactResource() throws Exception {
|
||||
persistOneTimePollMessage(MESSAGE_ID);
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_recentActiveAutorenew() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "1-3-EXAMPLE-4-3-2010"));
|
||||
persistAutorenewPollMessage(clock.nowUtc().minusMonths(6), END_OF_TIME);
|
||||
|
@ -140,7 +142,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_oldActiveAutorenew() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "1-3-EXAMPLE-4-3-2009"));
|
||||
persistAutorenewPollMessage(clock.nowUtc().minusYears(2), END_OF_TIME);
|
||||
|
@ -156,7 +158,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
ImmutableMap.of("MSGID", "1-3-EXAMPLE-4-3-2009", "COUNT", "4")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_oldInactiveAutorenew() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "1-3-EXAMPLE-4-3-2010"));
|
||||
persistAutorenewPollMessage(clock.nowUtc().minusMonths(6), clock.nowUtc());
|
||||
|
@ -164,7 +166,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_ack_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_moreMessages() throws Exception {
|
||||
// Create five messages to be queued for retrieval, one of which will be acked.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
|
@ -177,28 +179,28 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
ImmutableMap.of("MSGID", "1-3-EXAMPLE-4-3-2011", "COUNT", "4")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_noSuchMessage() throws Exception {
|
||||
assertTransactionalFlow(true);
|
||||
Exception e = assertThrows(MessageDoesNotExistException.class, this::runFlow);
|
||||
assertThat(e).hasMessageThat().contains(String.format("(1-3-EXAMPLE-4-%d-2011)", MESSAGE_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_invalidId_tooFewComponents() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "1-2-3"));
|
||||
assertTransactionalFlow(true);
|
||||
assertThrows(InvalidMessageIdException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_invalidId_tooManyComponents() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "2-2-ROID-4-3-1999-2007"));
|
||||
assertTransactionalFlow(true);
|
||||
assertThrows(InvalidMessageIdException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_contactPollMessage_withMissingYearField() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "2-2-ROID-4-3"));
|
||||
persistResource(
|
||||
|
@ -213,28 +215,28 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
assertThrows(InvalidMessageIdException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_invalidId_stringInsteadOfNumeric() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "ABC-12345"));
|
||||
assertTransactionalFlow(true);
|
||||
assertThrows(InvalidMessageIdException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_invalidEppResourceClassId() throws Exception {
|
||||
setEppInput("poll_ack.xml", ImmutableMap.of("MSGID", "999-1-1-1"));
|
||||
assertTransactionalFlow(true);
|
||||
assertThrows(InvalidMessageIdException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_missingId() throws Exception {
|
||||
setEppInput("poll_ack_missing_id.xml");
|
||||
assertTransactionalFlow(true);
|
||||
assertThrows(MissingMessageIdException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_differentRegistrar() throws Exception {
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
|
@ -248,7 +250,7 @@ class PollAckFlowTest extends FlowTestCase<PollAckFlow> {
|
|||
assertThrows(NotAuthorizedToAckMessageException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_messageInFuture() throws Exception {
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
|
|
|
@ -38,14 +38,16 @@ import google.registry.model.reporting.HistoryEntry;
|
|||
import google.registry.model.transfer.TransferResponse.ContactTransferResponse;
|
||||
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.ReplayExtension;
|
||||
import google.registry.testing.SetClockExtension;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link PollRequestFlow}. */
|
||||
@DualDatabaseTest
|
||||
class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
||||
|
||||
@Order(value = Order.DEFAULT - 3)
|
||||
|
@ -92,14 +94,14 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_domainTransferApproved() throws Exception {
|
||||
persistPendingTransferPollMessage();
|
||||
assertTransactionalFlow(false);
|
||||
runFlowAssertResponse(loadFile("poll_response_domain_transfer.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_clTridNotSpecified() throws Exception {
|
||||
setEppInput("poll_no_cltrid.xml");
|
||||
persistPendingTransferPollMessage();
|
||||
|
@ -107,7 +109,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_domain_transfer_no_cltrid.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_contactTransferPending() throws Exception {
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
persistResource(
|
||||
|
@ -130,7 +132,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_contact_transfer.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_domainPendingActionComplete() throws Exception {
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
|
@ -145,7 +147,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_domain_pending_notification.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_domainAutorenewMessage() throws Exception {
|
||||
persistResource(
|
||||
new PollMessage.Autorenew.Builder()
|
||||
|
@ -159,12 +161,12 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_autorenew.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_empty() throws Exception {
|
||||
runFlowAssertResponse(loadFile("poll_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_wrongRegistrar() throws Exception {
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
|
@ -176,7 +178,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_futurePollMessage() throws Exception {
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
|
@ -188,7 +190,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_futureAutorenew() throws Exception {
|
||||
persistResource(
|
||||
new PollMessage.Autorenew.Builder()
|
||||
|
@ -202,7 +204,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_empty.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_contactDelete() throws Exception {
|
||||
// Contact delete poll messages do not have any response data, so ensure that no
|
||||
// response data block is produced in the poll message.
|
||||
|
@ -223,7 +225,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_contact_delete.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_hostDelete() throws Exception {
|
||||
// Host delete poll messages do not have any response data, so ensure that no
|
||||
// response data block is produced in the poll message.
|
||||
|
@ -245,7 +247,7 @@ class PollRequestFlowTest extends FlowTestCase<PollRequestFlow> {
|
|||
runFlowAssertResponse(loadFile("poll_response_host_delete.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_messageIdProvided() throws Exception {
|
||||
setEppInput("poll_with_id.xml");
|
||||
assertTransactionalFlow(false);
|
||||
|
|
|
@ -25,21 +25,25 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
|||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.poll.PollMessageExternalKeyConverter.PollMessageExternalKeyParseException;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectExtension;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link PollMessageExternalKeyConverter}. */
|
||||
@DualDatabaseTest
|
||||
public class PollMessageExternalKeyConverterTest {
|
||||
|
||||
@RegisterExtension
|
||||
|
@ -55,21 +59,23 @@ public class PollMessageExternalKeyConverterTest {
|
|||
void beforeEach() {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
createTld("foobar");
|
||||
historyEntry = persistResource(new HistoryEntry.Builder()
|
||||
.setParent(persistActiveDomain("foo.foobar"))
|
||||
.setType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.setPeriod(Period.create(1, Period.Unit.YEARS))
|
||||
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
|
||||
.setModificationTime(clock.nowUtc())
|
||||
.setClientId("foo")
|
||||
.setTrid(Trid.create("ABC-123", "server-trid"))
|
||||
.setBySuperuser(false)
|
||||
.setReason("reason")
|
||||
.setRequestedByRegistrar(false)
|
||||
.build());
|
||||
historyEntry =
|
||||
persistResource(
|
||||
new DomainHistory.Builder()
|
||||
.setParent(persistActiveDomain("foo.foobar"))
|
||||
.setType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.setPeriod(Period.create(1, Period.Unit.YEARS))
|
||||
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
|
||||
.setModificationTime(clock.nowUtc())
|
||||
.setClientId("TheRegistrar")
|
||||
.setTrid(Trid.create("ABC-123", "server-trid"))
|
||||
.setBySuperuser(false)
|
||||
.setReason("reason")
|
||||
.setRequestedByRegistrar(false)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_domain() {
|
||||
PollMessage.OneTime pollMessage =
|
||||
persistResource(
|
||||
|
@ -80,14 +86,14 @@ public class PollMessageExternalKeyConverterTest {
|
|||
.setParent(historyEntry)
|
||||
.build());
|
||||
assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("1-2-FOOBAR-4-5-2007");
|
||||
assertThat(parsePollMessageExternalId("1-2-FOOBAR-4-5-2007"))
|
||||
.isEqualTo(Key.create(pollMessage));
|
||||
assertVKeysEqual(parsePollMessageExternalId("1-2-FOOBAR-4-5-2007"), pollMessage.createVKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_contact() {
|
||||
historyEntry =
|
||||
persistResource(historyEntry.asBuilder().setParent(persistActiveContact("tim")).build());
|
||||
persistResource(
|
||||
DatabaseHelper.createHistoryEntryForEppResource(persistActiveContact("tim")));
|
||||
PollMessage.OneTime pollMessage =
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
|
@ -96,14 +102,15 @@ public class PollMessageExternalKeyConverterTest {
|
|||
.setMsg("Test poll message")
|
||||
.setParent(historyEntry)
|
||||
.build());
|
||||
assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("2-5-ROID-4-6-2007");
|
||||
assertThat(parsePollMessageExternalId("2-5-ROID-4-6-2007")).isEqualTo(Key.create(pollMessage));
|
||||
assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("2-5-ROID-6-7-2007");
|
||||
assertVKeysEqual(parsePollMessageExternalId("2-5-ROID-6-7-2007"), pollMessage.createVKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_host() {
|
||||
historyEntry =
|
||||
persistResource(historyEntry.asBuilder().setParent(persistActiveHost("time.zyx")).build());
|
||||
persistResource(
|
||||
DatabaseHelper.createHistoryEntryForEppResource(persistActiveHost("time.xyz")));
|
||||
PollMessage.OneTime pollMessage =
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
|
@ -112,18 +119,18 @@ public class PollMessageExternalKeyConverterTest {
|
|||
.setMsg("Test poll message")
|
||||
.setParent(historyEntry)
|
||||
.build());
|
||||
assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("3-5-ROID-4-6-2007");
|
||||
assertThat(parsePollMessageExternalId("3-5-ROID-4-6-2007")).isEqualTo(Key.create(pollMessage));
|
||||
assertThat(makePollMessageExternalId(pollMessage)).isEqualTo("3-5-ROID-6-7-2007");
|
||||
assertVKeysEqual(parsePollMessageExternalId("3-5-ROID-6-7-2007"), pollMessage.createVKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_missingYearField() {
|
||||
assertThrows(
|
||||
PollMessageExternalKeyParseException.class,
|
||||
() -> parsePollMessageExternalId("1-2-FOOBAR-4-5"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_invalidEppResourceTypeId() {
|
||||
// Populate the testdata correctly as for 1-2-FOOBAR-4-5 so we know that the only thing that
|
||||
// is wrong here is the EppResourceTypeId.
|
||||
|
@ -133,24 +140,36 @@ public class PollMessageExternalKeyConverterTest {
|
|||
() -> parsePollMessageExternalId("4-2-FOOBAR-4-5-2007"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_tooFewComponentParts() {
|
||||
assertThrows(
|
||||
PollMessageExternalKeyParseException.class,
|
||||
() -> parsePollMessageExternalId("1-3-EXAMPLE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_tooManyComponentParts() {
|
||||
assertThrows(
|
||||
PollMessageExternalKeyParseException.class,
|
||||
() -> parsePollMessageExternalId("1-3-EXAMPLE-4-5-2007-2009"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_nonNumericIds() {
|
||||
assertThrows(
|
||||
PollMessageExternalKeyParseException.class,
|
||||
() -> parsePollMessageExternalId("A-B-FOOBAR-D-E-F"));
|
||||
}
|
||||
|
||||
// We may have VKeys of slightly varying types, e.g. VKey<PollMessage> (superclass) and
|
||||
// VKey<PollMessage.OneTime> (subclass). We should treat these as equal since the DB does.
|
||||
private static void assertVKeysEqual(
|
||||
VKey<? extends PollMessage> one, VKey<? extends PollMessage> two) {
|
||||
assertThat(
|
||||
one.getKind().isAssignableFrom(two.getKind())
|
||||
|| two.getKind().isAssignableFrom(one.getKind()))
|
||||
.isTrue();
|
||||
assertThat(one.getSqlKey()).isEqualTo(two.getSqlKey());
|
||||
assertThat(one.getOfyKey()).isEqualTo(two.getOfyKey());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,7 @@ import google.registry.tmch.LordnTaskUtils;
|
|||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
@ -1208,6 +1209,7 @@ public class DatabaseHelper {
|
|||
.setType(getHistoryEntryType(parentResource))
|
||||
.setModificationTime(DateTime.now(DateTimeZone.UTC))
|
||||
.setParent(parentResource)
|
||||
.setClientId(parentResource.getPersistedCurrentSponsorClientId())
|
||||
.build());
|
||||
}
|
||||
|
||||
|
@ -1329,5 +1331,19 @@ public class DatabaseHelper {
|
|||
return transactIfJpaTm(() -> tm().loadAllOf(clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the set of entities by their keys from the DB.
|
||||
*
|
||||
* <p>If the transaction manager is Cloud SQL, then this creates an inner wrapping transaction for
|
||||
* convenience, so you don't need to wrap it in a transaction at the callsite.
|
||||
*
|
||||
* <p>Nonexistent keys / entities are absent from the resulting map, but no {@link
|
||||
* NoSuchElementException} will be thrown.
|
||||
*/
|
||||
public static <T> ImmutableMap<VKey<? extends T>, T> loadByKeysIfPresent(
|
||||
Iterable<? extends VKey<? extends T>> keys) {
|
||||
return transactIfJpaTm(() -> tm().loadByKeysIfPresent(keys));
|
||||
}
|
||||
|
||||
private DatabaseHelper() {}
|
||||
}
|
||||
|
|
|
@ -16,39 +16,59 @@ package google.registry.tools;
|
|||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.loadByKeys;
|
||||
import static google.registry.testing.DatabaseHelper.loadByKeysIfPresent;
|
||||
import static google.registry.testing.DatabaseHelper.newDomainBase;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.poll.PollMessage.Autorenew;
|
||||
import google.registry.model.poll.PollMessage.OneTime;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectExtension;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link AckPollMessagesCommand}. */
|
||||
@DualDatabaseTest
|
||||
public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesCommand> {
|
||||
|
||||
private FakeClock clock = new FakeClock(DateTime.parse("2015-02-04T08:16:32.064Z"));
|
||||
|
||||
@RegisterExtension public final InjectExtension inject = new InjectExtension();
|
||||
|
||||
private DomainHistory domainHistory;
|
||||
|
||||
@BeforeEach
|
||||
final void beforeEach() {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
command.clock = clock;
|
||||
createTld("tld");
|
||||
DomainBase domain = newDomainBase("example.tld").asBuilder().setRepoId("FSDGS-TLD").build();
|
||||
persistResource(domain);
|
||||
domainHistory =
|
||||
persistResource(
|
||||
new DomainHistory.Builder()
|
||||
.setModificationTime(clock.nowUtc())
|
||||
.setDomainRepoId(domain.getRepoId())
|
||||
.setType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.setId(2406L)
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_doesntDeletePollMessagesInFuture() throws Exception {
|
||||
VKey<OneTime> pm1 =
|
||||
persistPollMessage(316L, DateTime.parse("2014-01-01T22:33:44Z"), "foobar").createVKey();
|
||||
|
@ -60,7 +80,7 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
persistPollMessage(123L, DateTime.parse("2015-09-01T22:33:44Z"), "notme");
|
||||
VKey<OneTime> pm4 = futurePollMessage.createVKey();
|
||||
runCommand("-c", "TheRegistrar");
|
||||
assertThat(tm().loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3, pm4)).values())
|
||||
assertThat(loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3, pm4)).values())
|
||||
.containsExactly(futurePollMessage);
|
||||
assertInStdout(
|
||||
"1-FSDGS-TLD-2406-624-2013,2013-05-01T22:33:44.000Z,ninelives",
|
||||
|
@ -69,7 +89,7 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
assertNotInStdout("1-FSDGS-TLD-2406-123-2015,2015-09-01T22:33:44.000Z,notme");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_resavesAutorenewPollMessages() throws Exception {
|
||||
VKey<OneTime> pm1 =
|
||||
persistPollMessage(316L, DateTime.parse("2014-01-01T22:33:44Z"), "foobar").createVKey();
|
||||
|
@ -78,10 +98,8 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
Autorenew autorenew =
|
||||
persistResource(
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setId(624L)
|
||||
.setParentKey(
|
||||
Key.create(
|
||||
Key.create(DomainBase.class, "AAFSGS-TLD"), HistoryEntry.class, 99406L))
|
||||
.setId(625L)
|
||||
.setParentKey(domainHistory.createVKey().getOfyKey())
|
||||
.setEventTime(DateTime.parse("2011-04-15T22:33:44Z"))
|
||||
.setClientId("TheRegistrar")
|
||||
.setMsg("autorenew")
|
||||
|
@ -90,15 +108,15 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
autorenew.asBuilder().setEventTime(DateTime.parse("2012-04-15T22:33:44Z")).build();
|
||||
VKey<Autorenew> pm3 = autorenew.createVKey();
|
||||
runCommand("-c", "TheRegistrar");
|
||||
assertThat(tm().loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3)).values())
|
||||
assertThat(loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3)).values())
|
||||
.containsExactly(resaved);
|
||||
assertInStdout(
|
||||
"1-AAFSGS-TLD-99406-624-2011,2011-04-15T22:33:44.000Z,autorenew",
|
||||
"1-FSDGS-TLD-2406-625-2011,2011-04-15T22:33:44.000Z,autorenew",
|
||||
"1-FSDGS-TLD-2406-624-2013,2013-05-01T22:33:44.000Z,ninelives",
|
||||
"1-FSDGS-TLD-2406-316-2014,2014-01-01T22:33:44.000Z,foobar");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_deletesExpiredAutorenewPollMessages() throws Exception {
|
||||
VKey<OneTime> pm1 =
|
||||
persistPollMessage(316L, DateTime.parse("2014-01-01T22:33:44Z"), "foobar").createVKey();
|
||||
|
@ -107,10 +125,8 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
Autorenew autorenew =
|
||||
persistResource(
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setId(624L)
|
||||
.setParentKey(
|
||||
Key.create(
|
||||
Key.create(DomainBase.class, "AAFSGS-TLD"), HistoryEntry.class, 99406L))
|
||||
.setId(625L)
|
||||
.setParentKey(domainHistory.createVKey().getOfyKey())
|
||||
.setEventTime(DateTime.parse("2011-04-15T22:33:44Z"))
|
||||
.setAutorenewEndTime(DateTime.parse("2012-01-01T22:33:44Z"))
|
||||
.setClientId("TheRegistrar")
|
||||
|
@ -118,14 +134,14 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
.build());
|
||||
VKey<Autorenew> pm3 = autorenew.createVKey();
|
||||
runCommand("-c", "TheRegistrar");
|
||||
assertThat(tm().loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3))).isEmpty();
|
||||
assertThat(loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3))).isEmpty();
|
||||
assertInStdout(
|
||||
"1-AAFSGS-TLD-99406-624-2011,2011-04-15T22:33:44.000Z,autorenew",
|
||||
"1-FSDGS-TLD-2406-625-2011,2011-04-15T22:33:44.000Z,autorenew",
|
||||
"1-FSDGS-TLD-2406-624-2013,2013-05-01T22:33:44.000Z,ninelives",
|
||||
"1-FSDGS-TLD-2406-316-2014,2014-01-01T22:33:44.000Z,foobar");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_onlyDeletesPollMessagesMatchingMessage() throws Exception {
|
||||
VKey<OneTime> pm1 =
|
||||
persistPollMessage(316L, DateTime.parse("2014-01-01T22:33:44Z"), "food is good")
|
||||
|
@ -139,11 +155,11 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
persistPollMessage(123L, DateTime.parse("2015-09-01T22:33:44Z"), "time flies");
|
||||
VKey<OneTime> pm4 = notMatched2.createVKey();
|
||||
runCommand("-c", "TheRegistrar", "-m", "food");
|
||||
assertThat(tm().loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3, pm4)).values())
|
||||
assertThat(loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3, pm4)).values())
|
||||
.containsExactly(notMatched1, notMatched2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_onlyDeletesPollMessagesMatchingClientId() throws Exception {
|
||||
VKey<OneTime> pm1 =
|
||||
persistPollMessage(316L, DateTime.parse("2014-01-01T22:33:44Z"), "food is good")
|
||||
|
@ -155,20 +171,18 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setId(2474L)
|
||||
.setParentKey(
|
||||
Key.create(
|
||||
Key.create(DomainBase.class, "FSDGS-TLD"), HistoryEntry.class, 2406L))
|
||||
.setParentKey(domainHistory.createVKey().getOfyKey())
|
||||
.setClientId("NewRegistrar")
|
||||
.setEventTime(DateTime.parse("2013-06-01T22:33:44Z"))
|
||||
.setMsg("baaaahh")
|
||||
.build());
|
||||
VKey<OneTime> pm3 = notMatched.createVKey();
|
||||
runCommand("-c", "TheRegistrar");
|
||||
assertThat(tm().loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3)).values())
|
||||
assertThat(loadByKeysIfPresent(ImmutableList.of(pm1, pm2, pm3)).values())
|
||||
.containsExactly(notMatched);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_dryRunDoesntDeleteAnything() throws Exception {
|
||||
OneTime pm1 = persistPollMessage(316L, DateTime.parse("2014-01-01T22:33:44Z"), "foobar");
|
||||
OneTime pm2 = persistPollMessage(624L, DateTime.parse("2013-05-01T22:33:44Z"), "ninelives");
|
||||
|
@ -176,20 +190,22 @@ public class AckPollMessagesCommandTest extends CommandTestCase<AckPollMessagesC
|
|||
OneTime pm4 = persistPollMessage(123L, DateTime.parse("2015-09-01T22:33:44Z"), "notme");
|
||||
runCommand("-c", "TheRegistrar", "-d");
|
||||
assertThat(
|
||||
tm().loadByKeys(
|
||||
ImmutableList.of(pm1, pm2, pm3, pm4).stream()
|
||||
.map(OneTime::createVKey)
|
||||
.collect(toImmutableList()))
|
||||
.values())
|
||||
loadByKeys(
|
||||
ImmutableList.of(pm1, pm2, pm3, pm4).stream()
|
||||
.map(OneTime::createVKey)
|
||||
.collect(toImmutableList())))
|
||||
.containsExactly(pm1, pm2, pm3, pm4);
|
||||
}
|
||||
|
||||
private static OneTime persistPollMessage(long id, DateTime eventTime, String message) {
|
||||
private OneTime persistPollMessage(long id, DateTime eventTime, String message) {
|
||||
return persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setId(id)
|
||||
.setParentKey(
|
||||
Key.create(Key.create(DomainBase.class, "FSDGS-TLD"), HistoryEntry.class, 2406L))
|
||||
Key.create(
|
||||
Key.create(DomainBase.class, "FSDGS-TLD"),
|
||||
HistoryEntry.class,
|
||||
domainHistory.getId()))
|
||||
.setClientId("TheRegistrar")
|
||||
.setEventTime(eventTime)
|
||||
.setMsg(message)
|
||||
|
|
|
@ -510,14 +510,14 @@ class google.registry.model.poll.PendingActionNotificationResponse$NameOrId {
|
|||
}
|
||||
class google.registry.model.poll.PollMessage {
|
||||
@Id java.lang.Long id;
|
||||
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
|
||||
@Parent com.googlecode.objectify.Key<? extends google.registry.model.reporting.HistoryEntry> parent;
|
||||
java.lang.String clientId;
|
||||
java.lang.String msg;
|
||||
org.joda.time.DateTime eventTime;
|
||||
}
|
||||
class google.registry.model.poll.PollMessage$Autorenew {
|
||||
@Id java.lang.Long id;
|
||||
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
|
||||
@Parent com.googlecode.objectify.Key<? extends google.registry.model.reporting.HistoryEntry> parent;
|
||||
java.lang.String clientId;
|
||||
java.lang.String msg;
|
||||
java.lang.String targetId;
|
||||
|
@ -526,7 +526,7 @@ class google.registry.model.poll.PollMessage$Autorenew {
|
|||
}
|
||||
class google.registry.model.poll.PollMessage$OneTime {
|
||||
@Id java.lang.Long id;
|
||||
@Parent com.googlecode.objectify.Key<google.registry.model.reporting.HistoryEntry> parent;
|
||||
@Parent com.googlecode.objectify.Key<? extends google.registry.model.reporting.HistoryEntry> parent;
|
||||
java.lang.String clientId;
|
||||
java.lang.String msg;
|
||||
java.util.List<google.registry.model.poll.PendingActionNotificationResponse$ContactPendingActionNotificationResponse> contactPendingActionNotificationResponses;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue