Remove DNS pull queue (#2000)

This is the last dependency on GAE pull queue, therefore we can delete
the pull queue config from queue.xml as well.
This commit is contained in:
Lai Jiang
2023-05-04 13:21:53 -04:00
committed by GitHub
parent 68810f7a30
commit e14764b4c8
60 changed files with 324 additions and 2311 deletions
@@ -43,7 +43,6 @@ import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeLockHandler;
import google.registry.testing.FakeResponse;
import google.registry.testing.TaskQueueExtension;
import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
@@ -59,8 +58,6 @@ class DeleteExpiredDomainsActionTest {
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
private final FakeResponse response = new FakeResponse();
private DeleteExpiredDomainsAction action;
@@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadByEntitiesIfPresent;
import static google.registry.testing.DatabaseHelper.loadByEntity;
@@ -30,11 +31,9 @@ import static google.registry.testing.DatabaseHelper.persistSimpleResource;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static org.joda.time.DateTimeZone.UTC;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import com.google.common.collect.ImmutableSet;
import google.registry.config.RegistryEnvironment;
import google.registry.dns.DnsUtils;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingBase.Reason;
import google.registry.model.billing.BillingEvent;
@@ -47,7 +46,6 @@ import google.registry.model.tld.Tld.TldType;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DnsUtilsHelper;
import google.registry.testing.SystemPropertyExtension;
import java.util.Optional;
import java.util.Set;
@@ -72,9 +70,6 @@ class DeleteProberDataActionTest {
private DeleteProberDataAction action;
private final DnsUtils dnsUtils = mock(DnsUtils.class);
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
@BeforeEach
void beforeEach() {
// Entities in these two should not be touched.
@@ -99,7 +94,6 @@ class DeleteProberDataActionTest {
private void resetAction() {
action = new DeleteProberDataAction();
action.dnsUtils = dnsUtils;
action.isDryRun = false;
action.tlds = ImmutableSet.of();
action.registryAdminRegistrarId = "TheRegistrar";
@@ -201,7 +195,7 @@ class DeleteProberDataActionTest {
DateTime timeAfterDeletion = DateTime.now(UTC);
assertThat(loadByForeignKey(Domain.class, "blah.ib-any.test", timeAfterDeletion)).isEmpty();
assertThat(loadByEntity(domain).getDeletionTime()).isLessThan(timeAfterDeletion);
dnsUtilsHelper.assertDomainDnsRequests("blah.ib-any.test");
assertDomainDnsRequests("blah.ib-any.test");
}
@Test
@@ -218,7 +212,7 @@ class DeleteProberDataActionTest {
action.run();
assertThat(loadByForeignKey(Domain.class, "blah.ib-any.test", timeAfterDeletion)).isEmpty();
assertThat(loadByEntity(domain).getDeletionTime()).isLessThan(timeAfterDeletion);
dnsUtilsHelper.assertDomainDnsRequests("blah.ib-any.test");
assertDomainDnsRequests("blah.ib-any.test");
}
@Test
@@ -15,11 +15,12 @@
package google.registry.dns;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.assertHostDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequestsExcept;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistActiveSubordinateHost;
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -30,7 +31,6 @@ import google.registry.request.HttpException.NotFoundException;
import google.registry.request.RequestModule;
import google.registry.testing.CloudTasksHelper.CloudTasksHelperModule;
import google.registry.testing.FakeClock;
import google.registry.testing.TaskQueueExtension;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.http.HttpServletRequest;
@@ -43,18 +43,15 @@ import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for Dagger injection of the DNS package. */
public final class DnsInjectionTest {
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
private final HttpServletRequest req = mock(HttpServletRequest.class);
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
private final StringWriter httpOutput = new StringWriter();
private final FakeClock clock = new FakeClock(DateTime.parse("2014-01-01TZ"));
private DnsTestComponent component;
private DnsQueue dnsQueue;
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@BeforeEach
void beforeEach() throws Exception {
@@ -64,18 +61,18 @@ public final class DnsInjectionTest {
.requestModule(new RequestModule(req, rsp))
.cloudTasksHelperModule(new CloudTasksHelperModule(clock))
.build();
dnsQueue = component.dnsQueue();
createTld("lol");
}
@Test
void testReadDnsQueueAction_injectsAndWorks() {
void testReadDnsRefreshRequestsAction_injectsAndWorks() {
persistActiveSubordinateHost("ns1.example.lol", persistActiveDomain("example.lol"));
clock.advanceOneMilli();
dnsQueue.addDomainRefreshTask("example.lol");
DnsUtils.requestDomainDnsRefresh("example.lol");
when(req.getParameter("tld")).thenReturn("lol");
component.readDnsQueueAction().run();
assertNoDnsTasksEnqueued();
clock.advanceOneMilli();
component.readDnsRefreshRequestsAction().run();
assertNoDnsRequests();
}
@Test
@@ -84,7 +81,7 @@ public final class DnsInjectionTest {
when(req.getParameter("type")).thenReturn("domain");
when(req.getParameter("name")).thenReturn("example.lol");
component.refreshDns().run();
assertDnsTasksEnqueued("example.lol");
assertNoDnsRequestsExcept("example.lol");
}
@Test
@@ -102,7 +99,7 @@ public final class DnsInjectionTest {
when(req.getParameter("type")).thenReturn("host");
when(req.getParameter("name")).thenReturn("ns1.example.lol");
component.refreshDns().run();
assertDnsTasksEnqueued("ns1.example.lol");
assertHostDnsRequests("ns1.example.lol");
}
@Test
@@ -1,108 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.dns;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
import static google.registry.testing.TaskQueueHelper.assertTasksEnqueued;
import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.FakeClock;
import google.registry.testing.TaskQueueExtension;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
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 DnsQueue}. */
public class DnsQueueTest {
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
private DnsQueue dnsQueue;
private final FakeClock clock = new FakeClock(DateTime.parse("2010-01-01T10:00:00Z"));
@BeforeEach
void beforeEach() {
dnsQueue = DnsQueue.createForTesting(clock);
dnsQueue.leaseTasksBatchSize = 10;
}
@Test
void test_addHostRefreshTask_success() {
createTld("tld");
dnsQueue.addHostRefreshTask("octopus.tld");
assertTasksEnqueued(
"dns-pull",
new TaskMatcher()
.param("Target-Type", "HOST")
.param("Target-Name", "octopus.tld")
.param("Create-Time", "2010-01-01T10:00:00.000Z")
.param("tld", "tld"));
}
@Test
void test_addHostRefreshTask_failsOnUnknownTld() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> {
try {
dnsQueue.addHostRefreshTask("octopus.notatld");
} finally {
assertNoTasksEnqueued("dns-pull");
}
});
assertThat(thrown)
.hasMessageThat()
.contains("octopus.notatld is not a subordinate host to a known tld");
}
@Test
void test_addDomainRefreshTask_success() {
createTld("tld");
dnsQueue.addDomainRefreshTask("octopus.tld");
assertTasksEnqueued(
"dns-pull",
new TaskMatcher()
.param("Target-Type", "DOMAIN")
.param("Target-Name", "octopus.tld")
.param("Create-Time", "2010-01-01T10:00:00.000Z")
.param("tld", "tld"));
}
@Test
void test_addDomainRefreshTask_failsOnUnknownTld() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> {
try {
dnsQueue.addDomainRefreshTask("fake.notatld");
} finally {
assertNoTasksEnqueued("dns-pull");
}
});
assertThat(thrown).hasMessageThat().contains("TLD notatld does not exist");
}
}
@@ -35,7 +35,7 @@ import javax.inject.Singleton;
VoidDnsWriterModule.class,
})
interface DnsTestComponent {
DnsQueue dnsQueue();
RefreshDnsAction refreshDns();
ReadDnsQueueAction readDnsQueueAction();
ReadDnsRefreshRequestsAction readDnsRefreshRequestsAction();
}
@@ -20,20 +20,10 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadAllOf;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import google.registry.dns.DnsConstants.TargetType;
import google.registry.model.common.DatabaseMigrationStateSchedule;
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
import google.registry.dns.DnsUtils.TargetType;
import google.registry.model.common.DnsRefreshRequest;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
@@ -42,7 +32,6 @@ import java.util.Comparator;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -54,52 +43,22 @@ public class DnsUtilsTest {
private static final String domainName = "test.tld";
private static final String hostName = "ns1.test.tld";
private final DnsQueue dnsQueue = mock(DnsQueue.class);
private final DnsUtils dnsUtils = new DnsUtils(dnsQueue);
private final FakeClock clock = new FakeClock(DateTime.parse("2020-02-02T01:23:45Z"));
@RegisterExtension
JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@BeforeAll
static void beforeAll() {
DatabaseMigrationStateSchedule.useUncachedForTest();
}
@BeforeEach
void beforeEach() {
createTld(tld);
when(dnsQueue.getClock()).thenReturn(clock);
}
@Test
void testSuccess_hostRefresh_pullQueue() {
dnsUtils.requestHostDnsRefresh(hostName);
verify(dnsQueue).addHostRefreshTask(hostName);
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
}
@Test
void testSuccess_domainRefresh_pullQueue() {
dnsUtils.requestDomainDnsRefresh(domainName);
verify(dnsQueue).addDomainRefreshTask(domainName, Duration.ZERO);
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
}
@Test
void testSuccess_domainRefreshWithDelay_pullQueue() {
dnsUtils.requestDomainDnsRefresh(domainName, Duration.standardMinutes(3));
verify(dnsQueue).addDomainRefreshTask(domainName, Duration.standardMinutes(3));
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
}
@Test
void testFailure_hostRefresh_unmanagedHost() {
String unmanagedHostName = "ns1.another.example";
Assertions.assertThrows(
IllegalArgumentException.class, () -> dnsUtils.requestHostDnsRefresh(unmanagedHostName));
verify(dnsQueue, never()).addHostRefreshTask(anyString());
IllegalArgumentException.class, () -> DnsUtils.requestHostDnsRefresh(unmanagedHostName));
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
}
@@ -108,34 +67,27 @@ public class DnsUtilsTest {
String unmanagedDomainName = "another.example";
Assertions.assertThrows(
IllegalArgumentException.class,
() -> dnsUtils.requestDomainDnsRefresh(unmanagedDomainName));
verify(dnsQueue, never()).addDomainRefreshTask(anyString(), any(Duration.class));
() -> DnsUtils.requestDomainDnsRefresh(unmanagedDomainName));
assertThat(loadAllOf(DnsRefreshRequest.class)).isEmpty();
}
@Test
void testSuccess_hostRefresh() {
useDnsSql();
dnsUtils.requestHostDnsRefresh(hostName);
verify(dnsQueue, never()).addHostRefreshTask(anyString());
DnsUtils.requestHostDnsRefresh(hostName);
DnsRefreshRequest request = Iterables.getOnlyElement(loadAllOf(DnsRefreshRequest.class));
assertRequest(request, TargetType.HOST, hostName, tld, clock.nowUtc());
}
@Test
void testSuccess_domainRefresh() {
useDnsSql();
dnsUtils.requestDomainDnsRefresh(domainName);
verify(dnsQueue, never()).addDomainRefreshTask(anyString(), any(Duration.class));
DnsUtils.requestDomainDnsRefresh(domainName);
DnsRefreshRequest request = Iterables.getOnlyElement(loadAllOf(DnsRefreshRequest.class));
assertRequest(request, TargetType.DOMAIN, domainName, tld, clock.nowUtc());
}
@Test
void testSuccess_domainRefreshWithDelay() {
useDnsSql();
dnsUtils.requestDomainDnsRefresh(domainName, Duration.standardMinutes(3));
verify(dnsQueue, never()).addDomainRefreshTask(anyString(), any(Duration.class));
DnsUtils.requestDomainDnsRefresh(domainName, Duration.standardMinutes(3));
DnsRefreshRequest request = Iterables.getOnlyElement(loadAllOf(DnsRefreshRequest.class));
assertRequest(request, TargetType.DOMAIN, domainName, tld, clock.nowUtc().plusMinutes(3));
}
@@ -182,7 +134,7 @@ public class DnsUtilsTest {
// Requests within cooldown period not included.
requests =
dnsUtils.readAndUpdateRequestsWithLatestProcessTime("tld", Duration.standardMinutes(1), 4);
DnsUtils.readAndUpdateRequestsWithLatestProcessTime("tld", Duration.standardMinutes(1), 4);
assertThat(requests.size()).isEqualTo(1);
assertRequest(
requests.get(0),
@@ -195,7 +147,7 @@ public class DnsUtilsTest {
@Test
void testSuccess_deleteRequests() {
dnsUtils.deleteRequests(processRequests());
DnsUtils.deleteRequests(processRequests());
ImmutableList<DnsRefreshRequest> remainingRequests =
loadAllOf(DnsRefreshRequest.class).stream()
.sorted(Comparator.comparing(DnsRefreshRequest::getRequestTime))
@@ -222,31 +174,30 @@ public class DnsUtilsTest {
tm().transact(() -> tm().delete(remainingRequests.get(2)));
assertThat(loadAllOf(DnsRefreshRequest.class).size()).isEqualTo(2);
// Should not throw even though one of the request is already deleted.
dnsUtils.deleteRequests(remainingRequests);
DnsUtils.deleteRequests(remainingRequests);
assertThat(loadAllOf(DnsRefreshRequest.class).size()).isEqualTo(0);
}
private ImmutableList<DnsRefreshRequest> processRequests() {
useDnsSql();
createTld("example");
// Domain Included.
dnsUtils.requestDomainDnsRefresh("test1.tld", Duration.standardMinutes(1));
DnsUtils.requestDomainDnsRefresh("test1.tld", Duration.standardMinutes(1));
// This one should be returned before test1.tld, even though it's added later, because of
// the delay specified in test1.tld.
dnsUtils.requestDomainDnsRefresh("test2.tld");
DnsUtils.requestDomainDnsRefresh("test2.tld");
// Not included because the TLD is not under management.
dnsUtils.requestDomainDnsRefresh("something.example", Duration.standardMinutes(2));
DnsUtils.requestDomainDnsRefresh("something.example", Duration.standardMinutes(2));
clock.advanceBy(Duration.standardMinutes(3));
// Host included.
dnsUtils.requestHostDnsRefresh("ns1.test2.tld");
DnsUtils.requestHostDnsRefresh("ns1.test2.tld");
// Not included because the request time is in the future
dnsUtils.requestDomainDnsRefresh("test4.tld", Duration.standardMinutes(2));
DnsUtils.requestDomainDnsRefresh("test4.tld", Duration.standardMinutes(2));
// Included after the previous one. Same request time, order by insertion order (i.e. ID);
dnsUtils.requestDomainDnsRefresh("test5.tld");
DnsUtils.requestDomainDnsRefresh("test5.tld");
// Not included because batch size is exceeded;
dnsUtils.requestDomainDnsRefresh("test6.tld");
DnsUtils.requestDomainDnsRefresh("test6.tld");
clock.advanceBy(Duration.standardMinutes(1));
return dnsUtils.readAndUpdateRequestsWithLatestProcessTime(
return DnsUtils.readAndUpdateRequestsWithLatestProcessTime(
"tld", Duration.standardMinutes(1), 4);
}
@@ -268,26 +219,4 @@ public class DnsUtilsTest {
assertThat(request.getRequestTime()).isEqualTo(requestTime);
assertThat(request.getLastProcessTime()).isEqualTo(processTime);
}
private void useDnsSql() {
DateTime currentTime = clock.nowUtc();
clock.setTo(START_OF_TIME);
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.put(
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
.put(START_OF_TIME.plusMillis(8), MigrationState.NORDN_SQL)
.put(START_OF_TIME.plusMillis(9), MigrationState.DNS_SQL)
.build()));
clock.setTo(currentTime);
}
}
@@ -15,7 +15,6 @@
package google.registry.dns;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.dns.DnsConstants.DNS_PUBLISH_PUSH_QUEUE_NAME;
import static google.registry.dns.DnsModule.PARAM_DNS_WRITER;
import static google.registry.dns.DnsModule.PARAM_DOMAINS;
import static google.registry.dns.DnsModule.PARAM_HOSTS;
@@ -23,8 +22,13 @@ import static google.registry.dns.DnsModule.PARAM_LOCK_INDEX;
import static google.registry.dns.DnsModule.PARAM_NUM_PUBLISH_LOCKS;
import static google.registry.dns.DnsModule.PARAM_PUBLISH_TASK_ENQUEUED;
import static google.registry.dns.DnsModule.PARAM_REFRESH_REQUEST_TIME;
import static google.registry.dns.DnsUtils.DNS_PUBLISH_PUSH_QUEUE_NAME;
import static google.registry.dns.PublishDnsUpdatesAction.RETRIES_BEFORE_PERMANENT_FAILURE;
import static google.registry.request.RequestParameters.PARAM_TLD;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests;
import static google.registry.testing.DatabaseHelper.assertHostDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequestsExcept;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistActiveSubordinateHost;
@@ -54,7 +58,6 @@ import google.registry.request.HttpException.ServiceUnavailableException;
import google.registry.request.lock.LockHandler;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.CloudTasksHelper.TaskMatcher;
import google.registry.testing.DnsUtilsHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeLockHandler;
import google.registry.testing.FakeResponse;
@@ -83,8 +86,6 @@ public class PublishDnsUpdatesActionTest {
private final FakeLockHandler lockHandler = new FakeLockHandler(true);
private final DnsWriter dnsWriter = mock(DnsWriter.class);
private final DnsMetrics dnsMetrics = mock(DnsMetrics.class);
private final DnsUtils dnsUtils = mock(DnsUtils.class);
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
private PublishDnsUpdatesAction action;
private InternetAddress outgoingRegistry;
@@ -95,6 +96,7 @@ public class PublishDnsUpdatesActionTest {
@BeforeEach
void beforeEach() throws Exception {
createTld("xn--q9jyb4c");
createTld("com");
outgoingRegistry = new InternetAddress("outgoing@registry.example");
registrySupportEmail = Lazies.of(new InternetAddress("registry@test.com"));
registryCcEmail = Lazies.of(new InternetAddress("registry-cc@test.com"));
@@ -161,7 +163,6 @@ public class PublishDnsUpdatesActionTest {
outgoingRegistry,
Optional.ofNullable(retryCount),
Optional.empty(),
dnsUtils,
new DnsWriterProxy(ImmutableMap.of("correctWriter", dnsWriter)),
dnsMetrics,
lockHandler,
@@ -195,7 +196,7 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
assertThat(response.getStatus()).isEqualTo(SC_OK);
}
@@ -222,7 +223,7 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
assertThat(response.getStatus()).isEqualTo(SC_OK);
}
@@ -275,7 +276,7 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -495,7 +496,7 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -525,7 +526,7 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -553,7 +554,7 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -579,9 +580,9 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertDomainDnsRequests("example.com");
dnsUtilsHelper.assertHostDnsRequests("ns1.example.com");
dnsUtilsHelper.assertNoMoreDnsRequests();
assertDomainDnsRequests("example.com");
assertHostDnsRequests("ns1.example.com");
assertNoDnsRequestsExcept("example.com", "ns1.example.com");
}
@Test
@@ -607,9 +608,9 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertDomainDnsRequests("example.com");
dnsUtilsHelper.assertHostDnsRequests("ns1.example.com");
dnsUtilsHelper.assertNoMoreDnsRequests();
assertDomainDnsRequests("example.com");
assertHostDnsRequests("ns1.example.com");
assertNoDnsRequestsExcept("example.com", "ns1.example.com");
}
@Test
@@ -631,11 +632,12 @@ public class PublishDnsUpdatesActionTest {
Duration.standardHours(2),
Duration.standardHours(1));
verifyNoMoreInteractions(dnsMetrics);
dnsUtilsHelper.assertDomainDnsRequests("example.com");
dnsUtilsHelper.assertDomainDnsRequests("example2.com");
dnsUtilsHelper.assertHostDnsRequests("ns1.example.com");
dnsUtilsHelper.assertHostDnsRequests("ns2.example.com");
dnsUtilsHelper.assertHostDnsRequests("ns1.example2.com");
dnsUtilsHelper.assertNoMoreDnsRequests();
assertDomainDnsRequests("example.com");
assertDomainDnsRequests("example2.com");
assertHostDnsRequests("ns1.example.com");
assertHostDnsRequests("ns2.example.com");
assertHostDnsRequests("ns1.example2.com");
assertNoDnsRequestsExcept(
"example.com", "example2.com", "ns1.example.com", "ns2.example.com", "ns1.example2.com");
}
}
@@ -1,500 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.dns;
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Lists.transform;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.dns.DnsConstants.DNS_PUBLISH_PUSH_QUEUE_NAME;
import static google.registry.dns.DnsConstants.DNS_PULL_QUEUE_NAME;
import static google.registry.dns.DnsConstants.DNS_TARGET_CREATE_TIME_PARAM;
import static google.registry.dns.DnsConstants.DNS_TARGET_NAME_PARAM;
import static google.registry.dns.DnsConstants.DNS_TARGET_TYPE_PARAM;
import static google.registry.request.RequestParameters.PARAM_TLD;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.persistResource;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.cloud.tasks.v2.HttpMethod;
import com.google.cloud.tasks.v2.Task;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.hash.Hashing;
import com.google.common.net.InternetDomainName;
import google.registry.dns.DnsConstants.TargetType;
import google.registry.model.tld.Tld;
import google.registry.model.tld.Tld.TldType;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.CloudTasksHelper.TaskMatcher;
import google.registry.testing.FakeClock;
import google.registry.testing.TaskQueueExtension;
import google.registry.testing.TaskQueueHelper;
import google.registry.testing.UriParameters;
import java.nio.charset.StandardCharsets;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junitpioneer.jupiter.RetryingTest;
/** Unit tests for {@link ReadDnsQueueAction}. */
public class ReadDnsQueueActionTest {
private static final int TEST_TLD_UPDATE_BATCH_SIZE = 100;
private DnsQueue dnsQueue;
// Because of a bug in the queue test environment - b/73372999 - we must set the fake date of the
// test in the future. Set to year 3000 so it'll remain in the future for a very long time.
private final FakeClock clock = new FakeClock(DateTime.parse("3000-01-01TZ"));
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
@BeforeEach
void beforeEach() {
// Because of b/73372999 - the FakeClock can't be in the past, or the TaskQueues stop working.
// To make sure it's never in the past, we set the date far-far into the future
clock.setTo(DateTime.parse("3000-01-01TZ"));
createTlds("com", "net", "example", "multilock.uk");
persistResource(Tld.get("com").asBuilder().setDnsWriters(ImmutableSet.of("comWriter")).build());
persistResource(Tld.get("net").asBuilder().setDnsWriters(ImmutableSet.of("netWriter")).build());
persistResource(
Tld.get("example")
.asBuilder()
.setTldType(TldType.TEST)
.setDnsWriters(ImmutableSet.of("exampleWriter"))
.build());
persistResource(
Tld.get("multilock.uk")
.asBuilder()
.setNumDnsPublishLocks(1000)
.setDnsWriters(ImmutableSet.of("multilockWriter"))
.build());
dnsQueue = DnsQueue.createForTesting(clock);
}
private void run() {
ReadDnsQueueAction action =
new ReadDnsQueueAction(
TEST_TLD_UPDATE_BATCH_SIZE,
Duration.standardSeconds(10),
Optional.empty(),
clock,
dnsQueue,
Hashing.murmur3_32(),
cloudTasksHelper.getTestCloudTasksUtils());
// Advance the time a little, to ensure that leaseTasks() returns all tasks.
clock.advanceBy(Duration.standardHours(1));
action.run();
}
private static TaskOptions createRefreshTask(String name, TargetType type) {
TaskOptions options =
TaskOptions.Builder.withMethod(TaskOptions.Method.PULL)
.param(DNS_TARGET_TYPE_PARAM, type.toString())
.param(DNS_TARGET_NAME_PARAM, name)
.param(DNS_TARGET_CREATE_TIME_PARAM, "3000-01-01TZ");
String tld = InternetDomainName.from(name).parts().reverse().get(0);
return options.param("tld", tld);
}
private static TaskQueueHelper.TaskMatcher createDomainRefreshTaskMatcher(String name) {
return new TaskQueueHelper.TaskMatcher()
.param(DNS_TARGET_NAME_PARAM, name)
.param(DNS_TARGET_TYPE_PARAM, TargetType.DOMAIN.toString());
}
private void assertTldsEnqueuedInPushQueue(ImmutableMultimap<String, String> tldsToDnsWriters) {
// By default, the publishDnsUpdates tasks will be enqueued one hour after the update items were
// created in the pull queue. This is because of the clock.advanceBy in run()
cloudTasksHelper.assertTasksEnqueued(
DNS_PUBLISH_PUSH_QUEUE_NAME,
transform(
tldsToDnsWriters.entries().asList(),
(Entry<String, String> tldToDnsWriter) ->
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("tld", tldToDnsWriter.getKey())
.param("dnsWriter", tldToDnsWriter.getValue())
.param("requestTime", "3000-01-01T00:00:00.000Z")
.param("enqueued", "3000-01-01T01:00:00.000Z")
// Single-lock TLDs should use lock 1 of 1 by default
.param("lockIndex", "1")
.param("numPublishLocks", "1")
.header("content-type", "application/x-www-form-urlencoded")));
}
@RetryingTest(4)
void testSuccess_methodPostIsDefault() {
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.net");
dnsQueue.addDomainRefreshTask("domain.example");
run();
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
cloudTasksHelper.assertTasksEnqueued(
DNS_PUBLISH_PUSH_QUEUE_NAME,
new TaskMatcher().method(HttpMethod.POST),
new TaskMatcher().method(HttpMethod.POST),
new TaskMatcher().method(HttpMethod.POST));
}
@RetryingTest(4)
void testSuccess_allSingleLockTlds() {
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.net");
dnsQueue.addDomainRefreshTask("domain.example");
run();
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
assertTldsEnqueuedInPushQueue(
ImmutableMultimap.of("com", "comWriter", "net", "netWriter", "example", "exampleWriter"));
}
@RetryingTest(4)
void testSuccess_moreUpdatesThanQueueBatchSize() {
// The task queue has a batch size of 1000 (that's the maximum number of items you can lease at
// once).
ImmutableList<String> domains =
IntStream.range(0, 1500)
.mapToObj(i -> String.format("domain_%04d.com", i))
.collect(toImmutableList());
domains.forEach(dnsQueue::addDomainRefreshTask);
run();
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
ImmutableList<Task> queuedTasks =
ImmutableList.copyOf(cloudTasksHelper.getTestTasksFor(DNS_PUBLISH_PUSH_QUEUE_NAME));
// ReadDnsQueueAction batches items per TLD in batches of size 100.
// So for 1500 items in the DNS queue, we expect 15 items in the push queue
assertThat(queuedTasks).hasSize(15);
// Check all the expected domains are indeed enqueued
assertThat(
queuedTasks.stream()
.flatMap(
task ->
UriParameters.parse(
task.getAppEngineHttpRequest()
.getBody()
.toString(StandardCharsets.UTF_8))
.get("domains")
.stream())
.flatMap(values -> Splitter.on(',').splitToStream(values)))
.containsExactlyElementsIn(domains);
}
@RetryingTest(4)
void testSuccess_twoDnsWriters() {
persistResource(
Tld.get("com")
.asBuilder()
.setDnsWriters(ImmutableSet.of("comWriter", "otherWriter"))
.build());
dnsQueue.addDomainRefreshTask("domain.com");
run();
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
assertTldsEnqueuedInPushQueue(ImmutableMultimap.of("com", "comWriter", "com", "otherWriter"));
}
@RetryingTest(4)
void testSuccess_differentUpdateTimes_usesMinimum() {
clock.setTo(DateTime.parse("3000-02-03TZ"));
dnsQueue.addDomainRefreshTask("domain1.com");
clock.setTo(DateTime.parse("3000-02-04TZ"));
dnsQueue.addDomainRefreshTask("domain2.com");
clock.setTo(DateTime.parse("3000-02-05TZ"));
dnsQueue.addDomainRefreshTask("domain3.com");
run();
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
cloudTasksHelper.assertTasksEnqueued(
DNS_PUBLISH_PUSH_QUEUE_NAME,
new TaskMatcher()
.param("enqueued", "3000-02-05T01:00:00.000Z")
.param("requestTime", "3000-02-03T00:00:00.000Z")
.param("tld", "com")
.param("dnsWriter", "comWriter")
.param("domains", "domain1.com,domain2.com,domain3.com")
.param("hosts", "")
.param("lockIndex", "1")
.param("numPublishLocks", "1"));
}
@RetryingTest(4)
void testSuccess_oneTldPaused_returnedToQueue() {
persistResource(Tld.get("net").asBuilder().setDnsPaused(true).build());
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.net");
dnsQueue.addDomainRefreshTask("domain.example");
run();
TaskQueueHelper.assertTasksEnqueued(
DNS_PULL_QUEUE_NAME, createDomainRefreshTaskMatcher("domain.net"));
assertTldsEnqueuedInPushQueue(
ImmutableMultimap.of("com", "comWriter", "example", "exampleWriter"));
}
@RetryingTest(4)
void testSuccess_oneTldUnknown_returnedToQueue() {
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.example");
QueueFactory.getQueue(DNS_PULL_QUEUE_NAME)
.add(
TaskOptions.Builder.withDefaults()
.method(TaskOptions.Method.PULL)
.param(DNS_TARGET_TYPE_PARAM, TargetType.DOMAIN.toString())
.param(DNS_TARGET_NAME_PARAM, "domain.unknown")
.param(DNS_TARGET_CREATE_TIME_PARAM, "3000-01-01TZ")
.param(PARAM_TLD, "unknown"));
run();
TaskQueueHelper.assertTasksEnqueued(
DNS_PULL_QUEUE_NAME, createDomainRefreshTaskMatcher("domain.unknown"));
assertTldsEnqueuedInPushQueue(
ImmutableMultimap.of("com", "comWriter", "example", "exampleWriter"));
}
@RetryingTest(4)
void testSuccess_corruptTaskTldMismatch_published() {
// TODO(mcilwain): what's the correct action to take in this case?
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.example");
QueueFactory.getQueue(DNS_PULL_QUEUE_NAME)
.add(
TaskOptions.Builder.withDefaults()
.method(TaskOptions.Method.PULL)
.param(DNS_TARGET_TYPE_PARAM, TargetType.DOMAIN.toString())
.param(DNS_TARGET_NAME_PARAM, "domain.wrongtld")
.param(DNS_TARGET_CREATE_TIME_PARAM, "3000-01-01TZ")
.param(PARAM_TLD, "net"));
run();
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
assertTldsEnqueuedInPushQueue(
ImmutableMultimap.of("com", "comWriter", "example", "exampleWriter", "net", "netWriter"));
}
@RetryingTest(4)
void testSuccess_corruptTaskNoTld_discarded() {
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.example");
QueueFactory.getQueue(DNS_PULL_QUEUE_NAME)
.add(
TaskOptions.Builder.withDefaults()
.method(TaskOptions.Method.PULL)
.param(DNS_TARGET_TYPE_PARAM, TargetType.DOMAIN.toString())
.param(DNS_TARGET_NAME_PARAM, "domain.net"));
run();
// The corrupt task isn't in the pull queue, but also isn't in the push queue
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
assertTldsEnqueuedInPushQueue(
ImmutableMultimap.of("com", "comWriter", "example", "exampleWriter"));
}
@RetryingTest(4)
void testSuccess_corruptTaskNoName_discarded() {
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.example");
QueueFactory.getQueue(DNS_PULL_QUEUE_NAME)
.add(
TaskOptions.Builder.withDefaults()
.method(TaskOptions.Method.PULL)
.param(DNS_TARGET_TYPE_PARAM, TargetType.DOMAIN.toString())
.param(PARAM_TLD, "net"));
run();
// The corrupt task isn't in the pull queue, but also isn't in the push queue
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
assertTldsEnqueuedInPushQueue(
ImmutableMultimap.of("com", "comWriter", "example", "exampleWriter"));
}
@RetryingTest(4)
void testSuccess_corruptTaskNoType_discarded() {
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.example");
QueueFactory.getQueue(DNS_PULL_QUEUE_NAME)
.add(
TaskOptions.Builder.withDefaults()
.method(TaskOptions.Method.PULL)
.param(DNS_TARGET_NAME_PARAM, "domain.net")
.param(PARAM_TLD, "net"));
run();
// The corrupt task isn't in the pull queue, but also isn't in the push queue
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
assertTldsEnqueuedInPushQueue(
ImmutableMultimap.of("com", "comWriter", "example", "exampleWriter"));
}
@RetryingTest(4)
void testSuccess_corruptTaskWrongType_discarded() {
dnsQueue.addDomainRefreshTask("domain.com");
dnsQueue.addDomainRefreshTask("domain.example");
QueueFactory.getQueue(DNS_PULL_QUEUE_NAME)
.add(
TaskOptions.Builder.withDefaults()
.method(TaskOptions.Method.PULL)
.param(DNS_TARGET_TYPE_PARAM, "Wrong type")
.param(DNS_TARGET_NAME_PARAM, "domain.net")
.param(PARAM_TLD, "net"));
run();
// The corrupt task isn't in the pull queue, but also isn't in the push queue
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
assertTldsEnqueuedInPushQueue(
ImmutableMultimap.of("com", "comWriter", "example", "exampleWriter"));
}
private static String makeCommaSeparatedRange(int from, int to, String format) {
return IntStream.range(from, to)
.mapToObj(i -> String.format(format, i))
.collect(Collectors.joining(","));
}
@RetryingTest(4)
void testSuccess_manyDomainsAndHosts() {
for (int i = 0; i < 150; i++) {
// 0: domain; 1: host 1; 2: host 2
for (int thingType = 0; thingType < 3; thingType++) {
for (String tld : ImmutableList.of("com", "net")) {
String domainName = String.format("domain%04d.%s", i, tld);
switch (thingType) {
case 1:
getQueue(DNS_PULL_QUEUE_NAME)
.add(createRefreshTask("ns1." + domainName, TargetType.HOST));
break;
case 2:
getQueue(DNS_PULL_QUEUE_NAME)
.add(createRefreshTask("ns2." + domainName, TargetType.HOST));
break;
default:
dnsQueue.addDomainRefreshTask(domainName);
break;
}
}
}
}
run();
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
cloudTasksHelper.assertTasksEnqueued(
DNS_PUBLISH_PUSH_QUEUE_NAME,
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", makeCommaSeparatedRange(0, 100, "domain%04d.com"))
.param("hosts", ""),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", makeCommaSeparatedRange(100, 150, "domain%04d.com"))
.param("hosts", makeCommaSeparatedRange(0, 50, "ns1.domain%04d.com")),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", "")
.param("hosts", makeCommaSeparatedRange(50, 150, "ns1.domain%04d.com")),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", "")
.param("hosts", makeCommaSeparatedRange(0, 100, "ns2.domain%04d.com")),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", "")
.param("hosts", makeCommaSeparatedRange(100, 150, "ns2.domain%04d.com")),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", makeCommaSeparatedRange(0, 100, "domain%04d.net"))
.param("hosts", ""),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", makeCommaSeparatedRange(100, 150, "domain%04d.net"))
.param("hosts", makeCommaSeparatedRange(0, 50, "ns1.domain%04d.net")),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", "")
.param("hosts", makeCommaSeparatedRange(50, 150, "ns1.domain%04d.net")),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", "")
.param("hosts", makeCommaSeparatedRange(0, 100, "ns2.domain%04d.net")),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("domains", "")
.param("hosts", makeCommaSeparatedRange(100, 150, "ns2.domain%04d.net")));
}
@RetryingTest(4)
void testSuccess_lockGroupsHostBySuperordinateDomain() {
dnsQueue.addDomainRefreshTask("hello.multilock.uk");
dnsQueue.addHostRefreshTask("ns1.abc.hello.multilock.uk");
dnsQueue.addHostRefreshTask("ns2.hello.multilock.uk");
dnsQueue.addDomainRefreshTask("another.multilock.uk");
dnsQueue.addHostRefreshTask("ns3.def.another.multilock.uk");
dnsQueue.addHostRefreshTask("ns4.another.multilock.uk");
run();
TaskQueueHelper.assertNoTasksEnqueued(DNS_PULL_QUEUE_NAME);
// Expect two different groups; in-balliwick hosts are locked with their superordinate domains.
cloudTasksHelper.assertTasksEnqueued(
DNS_PUBLISH_PUSH_QUEUE_NAME,
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("tld", "multilock.uk")
.param("dnsWriter", "multilockWriter")
.param("requestTime", "3000-01-01T00:00:00.000Z")
.param("enqueued", "3000-01-01T01:00:00.000Z")
.param("domains", "hello.multilock.uk")
.param("hosts", "ns1.abc.hello.multilock.uk,ns2.hello.multilock.uk")
.header("content-type", "application/x-www-form-urlencoded"),
new TaskMatcher()
.url(PublishDnsUpdatesAction.PATH)
.param("tld", "multilock.uk")
.param("dnsWriter", "multilockWriter")
.param("requestTime", "3000-01-01T00:00:00.000Z")
.param("enqueued", "3000-01-01T01:00:00.000Z")
.param("domains", "another.multilock.uk")
.param("hosts", "ns3.def.another.multilock.uk,ns4.another.multilock.uk")
.header("content-type", "application/x-www-form-urlencoded"));
}
}
@@ -15,10 +15,6 @@
package google.registry.dns;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
import static google.registry.model.common.DatabaseMigrationStateSchedule.set;
import static google.registry.model.common.DatabaseMigrationStateSchedule.useUncachedForTest;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadAllOf;
import static google.registry.testing.DatabaseHelper.persistResource;
@@ -38,9 +34,7 @@ import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Ordering;
import google.registry.dns.DnsConstants.TargetType;
import google.registry.dns.DnsUtils.TargetType;
import google.registry.model.common.DnsRefreshRequest;
import google.registry.model.common.DnsRefreshRequestTest;
import google.registry.model.tld.Tld;
@@ -54,7 +48,6 @@ import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -65,7 +58,6 @@ public class ReadDnsRefreshRequestsActionTest {
private final FakeClock clock = new FakeClock(DateTime.parse("2020-02-02T01:23:45Z"));
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(clock);
private final DnsUtils dnsUtils = new DnsUtils(null);
private final Optional<Integer> jitterSeconds = Optional.of(5);
@RegisterExtension
@@ -80,20 +72,13 @@ public class ReadDnsRefreshRequestsActionTest {
jitterSeconds,
"tld",
clock,
dnsUtils,
null,
cloudTasksHelper.getTestCloudTasksUtils()));
private ImmutableList<DnsRefreshRequest> requests;
@BeforeAll
static void beforeAll() {
useUncachedForTest();
}
@BeforeEach
void beforeEach() {
useDnsSql();
persistResource(
createTld("tld")
.asBuilder()
@@ -271,26 +256,4 @@ public class ReadDnsRefreshRequestsActionTest {
.isAtMost(Duration.standardSeconds(jitterSeconds.get()));
});
}
private void useDnsSql() {
DateTime currentTime = clock.nowUtc();
clock.setTo(START_OF_TIME);
tm().transact(
() ->
set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.put(
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
.put(START_OF_TIME.plusMillis(8), MigrationState.NORDN_SQL)
.put(START_OF_TIME.plusMillis(9), MigrationState.DNS_SQL)
.build()));
clock.setTo(currentTime);
}
}
@@ -15,20 +15,22 @@
package google.registry.dns;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests;
import static google.registry.testing.DatabaseHelper.assertHostDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequestsExcept;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistActiveHost;
import static google.registry.testing.DatabaseHelper.persistActiveSubordinateHost;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import google.registry.dns.DnsConstants.TargetType;
import google.registry.dns.DnsUtils.TargetType;
import google.registry.model.domain.Domain;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.request.HttpException.BadRequestException;
import google.registry.request.HttpException.NotFoundException;
import google.registry.testing.DnsUtilsHelper;
import google.registry.testing.FakeClock;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -41,12 +43,10 @@ public class RefreshDnsActionTest {
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private final DnsUtils dnsUtils = mock(DnsUtils.class);
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
private final FakeClock clock = new FakeClock();
private void run(TargetType type, String name) {
new RefreshDnsAction(name, type, clock, dnsUtils).run();
new RefreshDnsAction(name, type, clock).run();
}
@BeforeEach
@@ -58,9 +58,9 @@ public class RefreshDnsActionTest {
void testSuccess_host() {
Domain domain = persistActiveDomain("example.xn--q9jyb4c");
persistActiveSubordinateHost("ns1.example.xn--q9jyb4c", domain);
run(TargetType.HOST, "ns1.example.xn--q9jyb4c");
dnsUtilsHelper.assertHostDnsRequests("ns1.example.xn--q9jyb4c");
dnsUtilsHelper.assertNoMoreDnsRequests();
run(DnsUtils.TargetType.HOST, "ns1.example.xn--q9jyb4c");
assertHostDnsRequests("ns1.example.xn--q9jyb4c");
assertNoDnsRequestsExcept("ns1.example.xn--q9jyb4c");
}
@Test
@@ -72,9 +72,9 @@ public class RefreshDnsActionTest {
BadRequestException.class,
() -> {
try {
run(TargetType.HOST, "ns1.example.xn--q9jyb4c");
run(DnsUtils.TargetType.HOST, "ns1.example.xn--q9jyb4c");
} finally {
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
});
assertThat(thrown)
@@ -85,23 +85,25 @@ public class RefreshDnsActionTest {
@Test
void testSuccess_domain() {
persistActiveDomain("example.xn--q9jyb4c");
run(TargetType.DOMAIN, "example.xn--q9jyb4c");
dnsUtilsHelper.assertDomainDnsRequests("example.xn--q9jyb4c");
dnsUtilsHelper.assertNoMoreDnsRequests();
run(DnsUtils.TargetType.DOMAIN, "example.xn--q9jyb4c");
assertDomainDnsRequests("example.xn--q9jyb4c");
assertNoDnsRequestsExcept("example.xn--q9jyb4c");
}
@Test
void testFailure_unqualifiedName() {
assertThrows(BadRequestException.class, () -> run(TargetType.DOMAIN, "example"));
assertThrows(BadRequestException.class, () -> run(DnsUtils.TargetType.DOMAIN, "example"));
}
@Test
void testFailure_hostDoesNotExist() {
assertThrows(NotFoundException.class, () -> run(TargetType.HOST, "ns1.example.xn--q9jyb4c"));
assertThrows(
NotFoundException.class, () -> run(DnsUtils.TargetType.HOST, "ns1.example.xn--q9jyb4c"));
}
@Test
void testFailure_domainDoesNotExist() {
assertThrows(NotFoundException.class, () -> run(TargetType.DOMAIN, "example.xn--q9jyb4c"));
assertThrows(
NotFoundException.class, () -> run(DnsUtils.TargetType.DOMAIN, "example.xn--q9jyb4c"));
}
}
@@ -15,6 +15,8 @@
package google.registry.dns;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.newDomain;
import static google.registry.testing.DatabaseHelper.persistActiveHost;
@@ -23,14 +25,12 @@ import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted;
import static google.registry.testing.DatabaseHelper.persistResource;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.mockito.Mockito.mock;
import com.google.common.collect.ImmutableSet;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.Host;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.DnsUtilsHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import org.joda.time.DateTime;
@@ -42,8 +42,6 @@ import org.junit.jupiter.api.extension.RegisterExtension;
public class RefreshDnsOnHostRenameActionTest {
private final FakeClock clock = new FakeClock(DateTime.parse("2015-01-15T11:22:33Z"));
private final DnsUtils dnsUtils = mock(DnsUtils.class);
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
private final FakeResponse response = new FakeResponse();
@RegisterExtension
@@ -53,7 +51,7 @@ public class RefreshDnsOnHostRenameActionTest {
private RefreshDnsOnHostRenameAction action;
private void createAction(String hostKey) {
action = new RefreshDnsOnHostRenameAction(hostKey, response, dnsUtils);
action = new RefreshDnsOnHostRenameAction(hostKey, response);
}
@BeforeEach
@@ -75,7 +73,7 @@ public class RefreshDnsOnHostRenameActionTest {
persistDomainAsDeleted(newDomain("deleted.tld", host), clock.nowUtc().minusDays(1));
createAction(host.createVKey().stringify());
action.run();
dnsUtilsHelper.assertDomainDnsRequests("example.tld", "otherexample.tld");
assertDomainDnsRequests("example.tld", "otherexample.tld");
assertThat(response.getStatus()).isEqualTo(SC_OK);
}
@@ -83,7 +81,7 @@ public class RefreshDnsOnHostRenameActionTest {
void testFailure_nonexistentHost() {
createAction("kind:Host@sql:rO0ABXQABGJsYWg");
action.run();
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
assertThat(response.getPayload())
.isEqualTo("Host to refresh does not exist: VKey<Host>(sql:blah)");
@@ -95,7 +93,7 @@ public class RefreshDnsOnHostRenameActionTest {
persistResource(newDomain("example.tld", host));
createAction(host.createVKey().stringify());
action.run();
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
assertThat(response.getPayload())
.isEqualTo("Host to refresh is already deleted: ns1.example.tld");
@@ -47,7 +47,6 @@ import google.registry.model.tld.Tld;
import google.registry.model.tld.Tld.TldState;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.TaskQueueExtension;
import google.registry.tmch.TmchData;
import google.registry.tmch.TmchTestData;
import org.joda.money.Money;
@@ -72,8 +71,6 @@ class EppLifecycleDomainTest extends EppTestCase {
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
@BeforeEach
void beforeEach() {
createTlds("example", "tld");
@@ -27,7 +27,6 @@ import google.registry.model.domain.Domain;
import google.registry.model.host.Host;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.TaskQueueExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -39,8 +38,6 @@ class EppLifecycleHostTest extends EppTestCase {
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
@Test
void testLifecycle() throws Exception {
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
@@ -36,7 +36,6 @@ import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationT
import google.registry.testing.EppLoader;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
import google.registry.testing.TaskQueueExtension;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -51,8 +50,6 @@ class EppPointInTimeTest {
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@RegisterExtension final TaskQueueExtension taskQueue = new TaskQueueExtension();
private EppLoader eppLoader;
@BeforeEach
@@ -23,8 +23,6 @@ import google.registry.batch.AsyncTaskEnqueuerTest;
import google.registry.batch.CloudTasksUtils;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.dns.DnsQueue;
import google.registry.dns.DnsUtils;
import google.registry.flows.custom.CustomLogicFactory;
import google.registry.flows.custom.TestCustomLogicFactory;
import google.registry.flows.domain.DomainFlowTmchUtils;
@@ -32,7 +30,6 @@ import google.registry.monitoring.whitebox.EppMetric;
import google.registry.request.RequestScope;
import google.registry.request.lock.LockHandler;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.DnsUtilsHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeLockHandler;
import google.registry.testing.FakeSleeper;
@@ -54,23 +51,17 @@ public interface EppTestComponent {
class FakesAndMocksModule {
private AsyncTaskEnqueuer asyncTaskEnqueuer;
private DnsQueue dnsQueue;
private DomainFlowTmchUtils domainFlowTmchUtils;
private EppMetric.Builder metricBuilder;
private FakeClock clock;
private FakeLockHandler lockHandler;
private Sleeper sleeper;
private CloudTasksHelper cloudTasksHelper;
private DnsUtilsHelper dnsUtilsHelper;
public CloudTasksHelper getCloudTasksHelper() {
return cloudTasksHelper;
}
public DnsUtilsHelper getDnsUtilsHelper() {
return dnsUtilsHelper;
}
public EppMetric.Builder getMetricBuilder() {
return metricBuilder;
}
@@ -85,11 +76,9 @@ public interface EppTestComponent {
new DomainFlowTmchUtils(
new TmchXmlSignature(new TmchCertificateAuthority(TmchCaMode.PILOT, clock)));
instance.sleeper = new FakeSleeper(instance.clock);
instance.dnsQueue = DnsQueue.createForTesting(clock);
instance.metricBuilder = EppMetric.builderForRequest(clock);
instance.lockHandler = new FakeLockHandler(true);
instance.cloudTasksHelper = cloudTasksHelper;
instance.dnsUtilsHelper = new DnsUtilsHelper();
return instance;
}
@@ -103,11 +92,6 @@ public interface EppTestComponent {
return cloudTasksHelper.getTestCloudTasksUtils();
}
@Provides
DnsUtils provideDnsUtils() {
return dnsUtilsHelper.getDnsUtils();
}
@Provides
Clock provideClock() {
return clock;
@@ -123,11 +107,6 @@ public interface EppTestComponent {
return new TestCustomLogicFactory();
}
@Provides
DnsQueue provideDnsQueue() {
return dnsQueue;
}
@Provides
DomainFlowTmchUtils provideDomainFlowTmchUtils() {
return domainFlowTmchUtils;
@@ -45,7 +45,6 @@ import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DnsUtilsHelper;
import google.registry.testing.EppLoader;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
@@ -85,7 +84,6 @@ public abstract class FlowTestCase<F extends Flow> {
protected TransportCredentials credentials = new PasswordOnlyTransportCredentials();
protected EppRequestSource eppRequestSource = EppRequestSource.UNIT_TEST;
protected CloudTasksHelper cloudTasksHelper;
protected DnsUtilsHelper dnsUtilsHelper;
private EppMetric.Builder eppMetricBuilder;
@@ -217,7 +215,6 @@ public abstract class FlowTestCase<F extends Flow> {
FakesAndMocksModule fakesAndMocksModule = FakesAndMocksModule.create(clock);
cloudTasksHelper = fakesAndMocksModule.getCloudTasksHelper();
dnsUtilsHelper = fakesAndMocksModule.getDnsUtilsHelper();
// Run the flow.
return DaggerEppTestComponent.builder()
.fakesAndMocksModule(fakesAndMocksModule)
@@ -14,12 +14,10 @@
package google.registry.flows;
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_RESOURCE_KEY;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.LogsSubject.assertAboutLogs;
import static google.registry.testing.TaskQueueHelper.assertTasksEnqueued;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -30,7 +28,6 @@ import google.registry.model.contact.ContactBase;
import google.registry.model.contact.ContactHistory;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.eppcommon.Trid;
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.host.HostBase;
@@ -39,14 +36,13 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.tmch.ClaimsList;
import google.registry.model.tmch.ClaimsListDao;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.testing.TestCacheExtension;
import google.registry.util.JdkLoggerConfig;
import google.registry.util.TypeUtils.TypeInstantiator;
import java.time.Duration;
import java.util.logging.Level;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.json.simple.JSONValue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -64,11 +60,11 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
@RegisterExtension
public final TestCacheExtension testCacheExtension =
new TestCacheExtension.Builder().withClaimsListCache(java.time.Duration.ofHours(6)).build();
new TestCacheExtension.Builder().withClaimsListCache(Duration.ofHours(6)).build();
@BeforeEach
void beforeResourceFlowTestCase() {
// Attach TestLogHandler to the root logger so it has access to all log messages.
// Attach TestLogHandler to the root logger, so it has access to all log messages.
// Note that in theory for assertIcannReportingActivityFieldLogged() below it would suffice to
// attach it only to the FlowRunner logger, but for some reason this doesn't work for all flows.
JdkLoggerConfig.getConfig("").addHandler(logHandler);
@@ -110,22 +106,6 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
ClaimsListDao.save(ClaimsList.create(clock.nowUtc(), labelsToKeys));
}
/** Asserts the presence of a single enqueued async contact or host deletion */
protected <T extends EppResource> void assertAsyncDeletionTaskEnqueued(
T resource, String requestingClientId, Trid trid, boolean isSuperuser) {
TaskMatcher expected =
new TaskMatcher()
.etaDelta(Duration.standardSeconds(75), Duration.standardSeconds(105)) // expected: 90
.param(PARAM_RESOURCE_KEY, resource.createVKey().stringify())
.param("requestingClientId", requestingClientId)
.param("serverTransactionId", trid.getServerTransactionId())
.param("isSuperuser", Boolean.toString(isSuperuser))
.param("requestedTime", clock.nowUtc().toString());
trid.getClientTransactionId()
.ifPresent(clTrid -> expected.param("clientTransactionId", clTrid));
assertTasksEnqueued("async-delete-pull", expected);
}
protected void assertClientIdFieldLogged(String registrarId) {
assertAboutLogs()
.that(logHandler)
@@ -39,6 +39,8 @@ import static google.registry.model.tld.Tld.TldState.START_DATE_SUNRISE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.pricing.PricingEngineProxy.isDomainPremium;
import static google.registry.testing.DatabaseHelper.assertBillingEvents;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.assertPollMessagesForResource;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.createTlds;
@@ -176,7 +178,6 @@ import google.registry.model.tld.Tld.TldType;
import google.registry.monitoring.whitebox.EppMetric;
import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.TaskQueueExtension;
import google.registry.tmch.LordnTaskUtils.LordnPhase;
import google.registry.tmch.SmdrlCsvParser;
import google.registry.tmch.TmchData;
@@ -190,15 +191,12 @@ import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junitpioneer.jupiter.cartesian.CartesianTest;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
/** Unit tests for {@link DomainCreateFlow}. */
class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain> {
@RegisterExtension TaskQueueExtension taskQueue = new TaskQueueExtension();
private static final String CLAIMS_KEY = "2013041500/2/6/9/rJ1NrDO92vDsAzf7EQzgjX4R0000000001";
// This is a time when SMD itself is not valid, but its signing certificates are. It will
// trigger a different exception than when any signing cert is not valid yet.
@@ -378,7 +376,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
GracePeriod.create(
GracePeriodStatus.ADD, domain.getRepoId(), billingTime, "TheRegistrar", null),
createBillingEvent));
dnsUtilsHelper.assertDomainDnsRequests(getUniqueIdFromCommand());
assertDomainDnsRequests(getUniqueIdFromCommand());
}
private void assertNoLordn() throws Exception {
@@ -901,7 +899,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
persistContactsAndHosts("net");
runFlowAssertResponse(loadFile("domain_create_response_idn_minna.xml"));
assertSuccessfulCreate("xn--q9jyb4c", ImmutableSet.of());
dnsUtilsHelper.assertDomainDnsRequests("xn--abc-873b2e7eb1k8a4lpjvv.xn--q9jyb4c");
assertDomainDnsRequests("xn--abc-873b2e7eb1k8a4lpjvv.xn--q9jyb4c");
}
@Test
@@ -910,7 +908,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
persistContactsAndHosts();
runFlowAssertResponse(
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.tld")));
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -923,7 +921,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutDomains()
.that(reloadResourceByForeignKey())
.hasRegistrationExpirationTime(clock.nowUtc().plusYears(1));
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
}
@Test
@@ -941,7 +939,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
persistContactsAndHosts();
runFlowAssertResponse(loadFile("domain_create_response_claims.xml"));
assertSuccessfulCreate("tld", ImmutableSet.of());
dnsUtilsHelper.assertDomainDnsRequests("example-one.tld");
assertDomainDnsRequests("example-one.tld");
assertClaimsLordn();
}
@@ -970,7 +968,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
persistContactsAndHosts();
runFlowAssertResponse(loadFile("domain_create_response_claims.xml"));
assertSuccessfulCreate("tld", ImmutableSet.of(RESERVED), allocationToken);
dnsUtilsHelper.assertDomainDnsRequests("example-one.tld");
assertDomainDnsRequests("example-one.tld");
assertClaimsLordn();
assertAllocationTokenWasRedeemed("abcDEF23456");
}
@@ -983,7 +981,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
runFlowAssertResponse(
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.tld")));
assertSuccessfulCreate("tld", ImmutableSet.of());
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
}
@Test
@@ -1383,7 +1381,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
persistContactsAndHosts();
runFlowAssertResponse(loadFile("domain_create_response_claims.xml"));
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), allocationToken);
dnsUtilsHelper.assertDomainDnsRequests("example-one.tld");
assertDomainDnsRequests("example-one.tld");
assertClaimsLordn();
assertAllocationTokenWasRedeemed("abcDEF23456");
}
@@ -1463,7 +1461,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
"EXPIRATION_TIME",
SMD_VALID_TIME.plusYears(2).toString())));
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT, SUNRISE), allocationToken);
dnsUtilsHelper.assertDomainDnsRequests("test-validate.tld");
assertDomainDnsRequests("test-validate.tld");
assertSunriseLordn();
assertAllocationTokenWasRedeemed("abcDEF23456");
}
@@ -2123,7 +2121,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertSunriseLordn();
// Check for SERVER_HOLD status, no DNS tasks enqueued, and collision poll message.
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
Domain domain = reloadResourceByForeignKey();
assertThat(domain.getStatusValues()).contains(SERVER_HOLD);
assertPollMessagesWithCollisionOneTime(domain);
@@ -2140,7 +2138,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "badcrash.tld")));
// Check for SERVER_HOLD status, no DNS tasks enqueued, and collision poll message.
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
Domain domain = reloadResourceByForeignKey();
assertThat(domain.getStatusValues()).contains(SERVER_HOLD);
assertPollMessagesWithCollisionOneTime(domain);
@@ -34,6 +34,7 @@ import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_DELETE;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST;
import static google.registry.model.tld.Tld.TldState.PREDELEGATION;
import static google.registry.testing.DatabaseHelper.assertBillingEvents;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests;
import static google.registry.testing.DatabaseHelper.assertPollMessages;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
@@ -357,7 +358,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
// The add grace period is for a billable action, so it should trigger a cancellation.
assertAutorenewClosedAndCancellationCreatedFor(
graceBillingEvent, getOnlyHistoryEntryOfType(domain, DOMAIN_DELETE, DomainHistory.class));
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
// There should be no poll messages. The previous autorenew poll message should now be deleted.
assertThat(getPollMessages("TheRegistrar")).isEmpty();
}
@@ -744,7 +745,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.build());
DateTime eventTime = clock.nowUtc();
runFlowAssertResponse(loadFile("generic_success_response.xml"));
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
assertAutorenewClosedAndCancellationCreatedFor(
graceBillingEvent,
getOnlyHistoryEntryOfType(domain, DOMAIN_DELETE, DomainHistory.class),
@@ -762,7 +763,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.build());
clock.advanceOneMilli();
runFlowAssertResponse(loadFile("domain_delete_response_pending.xml"));
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
assertOnlyBillingEventIsClosedAutorenew("TheRegistrar");
}
@@ -17,6 +17,7 @@ package google.registry.flows.domain;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.testing.DatabaseHelper.assertBillingEvents;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests;
import static google.registry.testing.DatabaseHelper.assertPollMessages;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
@@ -188,7 +189,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
.and()
.hasLastEppUpdateRegistrarId("TheRegistrar");
assertThat(domain.getGracePeriods()).isEmpty();
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
// The poll message for the delete should now be gone. The only poll message should be the new
// autorenew poll message.
assertPollMessages(
@@ -256,7 +257,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
.and()
.hasLastEppUpdateRegistrarId("TheRegistrar");
assertThat(domain.getGracePeriods()).isEmpty();
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
// The poll message for the delete should now be gone. The only poll message should be the new
// autorenew poll message.
assertPollMessages(
@@ -22,15 +22,21 @@ import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.eppcommon.StatusValue.CLIENT_DELETE_PROHIBITED;
import static google.registry.model.eppcommon.StatusValue.CLIENT_HOLD;
import static google.registry.model.eppcommon.StatusValue.CLIENT_RENEW_PROHIBITED;
import static google.registry.model.eppcommon.StatusValue.CLIENT_TRANSFER_PROHIBITED;
import static google.registry.model.eppcommon.StatusValue.CLIENT_UPDATE_PROHIBITED;
import static google.registry.model.eppcommon.StatusValue.PENDING_DELETE;
import static google.registry.model.eppcommon.StatusValue.SERVER_DELETE_PROHIBITED;
import static google.registry.model.eppcommon.StatusValue.SERVER_HOLD;
import static google.registry.model.eppcommon.StatusValue.SERVER_RENEW_PROHIBITED;
import static google.registry.model.eppcommon.StatusValue.SERVER_TRANSFER_PROHIBITED;
import static google.registry.model.eppcommon.StatusValue.SERVER_UPDATE_PROHIBITED;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_UPDATE;
import static google.registry.model.tld.Tld.TldState.QUIET_PERIOD;
import static google.registry.testing.DatabaseHelper.assertBillingEvents;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.assertPollMessagesForResource;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
@@ -96,7 +102,6 @@ import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.secdns.DomainDsData;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.Host;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
@@ -204,7 +209,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
// Check that the domain was updated. These values came from the xml.
assertAboutDomains()
.that(domain)
.hasStatusValue(StatusValue.CLIENT_HOLD)
.hasStatusValue(CLIENT_HOLD)
.and()
.hasAuthInfoPwd("2BARfoo")
.and()
@@ -216,7 +221,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.and()
.hasNoAutorenewEndTime();
assertNoBillingEvents();
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
assertLastHistoryContainsResource(reloadResourceByForeignKey());
}
@@ -345,7 +350,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
assertThat(domain.getContacts()).hasSize(3);
assertThat(loadByKey(domain.getRegistrant()).getContactId()).isEqualTo("max_test_7");
assertNoBillingEvents();
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
}
@Test
@@ -453,13 +458,13 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
persistResource(
persistDomain()
.asBuilder()
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
.setStatusValues(ImmutableSet.of(CLIENT_UPDATE_PROHIBITED))
.build());
clock.advanceOneMilli();
runFlow();
assertAboutDomains()
.that(reloadResourceByForeignKey())
.doesNotHaveStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED);
.doesNotHaveStatusValue(CLIENT_UPDATE_PROHIBITED);
}
private void doSecDnsSuccessfulTest(
@@ -496,9 +501,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.map(ds -> ds.cloneWithDomainRepoId(resource.getRepoId()))
.collect(toImmutableSet()));
if (dnsTaskEnqueued) {
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
} else {
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
}
@@ -855,8 +860,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
void testSuccess_noBillingOnPreExistingServerStatus() throws Exception {
eppRequestSource = EppRequestSource.TOOL;
Domain addStatusDomain = persistActiveDomain(getUniqueIdFromCommand());
persistResource(
addStatusDomain.asBuilder().addStatusValue(StatusValue.SERVER_RENEW_PROHIBITED).build());
persistResource(addStatusDomain.asBuilder().addStatusValue(SERVER_RENEW_PROHIBITED).build());
doServerStatusBillingTest("domain_update_add_server_status.xml", false);
}
@@ -865,8 +869,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
eppRequestSource = EppRequestSource.TOOL;
persistReferencedEntities();
Domain removeStatusDomain = persistDomain();
persistResource(
removeStatusDomain.asBuilder().addStatusValue(StatusValue.SERVER_RENEW_PROHIBITED).build());
persistResource(removeStatusDomain.asBuilder().addStatusValue(SERVER_RENEW_PROHIBITED).build());
doServerStatusBillingTest("domain_update_remove_server_status.xml", true);
}
@@ -875,8 +878,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
eppRequestSource = EppRequestSource.TOOL;
persistReferencedEntities();
Domain changeStatusDomain = persistDomain();
persistResource(
changeStatusDomain.asBuilder().addStatusValue(StatusValue.SERVER_RENEW_PROHIBITED).build());
persistResource(changeStatusDomain.asBuilder().addStatusValue(SERVER_RENEW_PROHIBITED).build());
doServerStatusBillingTest("domain_update_change_server_status.xml", true);
}
@@ -906,14 +908,14 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
persistResource(
persistActiveDomain(getUniqueIdFromCommand())
.asBuilder()
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
.setStatusValues(ImmutableSet.of(CLIENT_UPDATE_PROHIBITED))
.build());
clock.advanceOneMilli();
runFlowAssertResponse(
CommitMode.LIVE, UserPrivileges.SUPERUSER, loadFile("generic_success_response.xml"));
assertAboutDomains()
.that(reloadResourceByForeignKey())
.hasStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED)
.hasStatusValue(CLIENT_UPDATE_PROHIBITED)
.and()
.hasStatusValue(SERVER_HOLD);
}
@@ -1318,7 +1320,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
persistResource(
DatabaseHelper.newDomain(getUniqueIdFromCommand())
.asBuilder()
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
.setStatusValues(ImmutableSet.of(CLIENT_UPDATE_PROHIBITED))
.build());
EppException thrown =
assertThrows(ResourceHasClientUpdateProhibitedException.class, this::runFlow);
@@ -1345,7 +1347,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
DatabaseHelper.newDomain(getUniqueIdFromCommand())
.asBuilder()
.setDeletionTime(clock.nowUtc().plusDays(1))
.addStatusValue(StatusValue.PENDING_DELETE)
.addStatusValue(PENDING_DELETE)
.build());
ResourceStatusProhibitsOperationException thrown =
assertThrows(ResourceStatusProhibitsOperationException.class, this::runFlow);
@@ -1500,7 +1502,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
loadByForeignKey(Contact.class, "mak21", clock.nowUtc())
.get()
.asBuilder()
.addStatusValue(StatusValue.PENDING_DELETE)
.addStatusValue(PENDING_DELETE)
.build());
clock.advanceOneMilli();
LinkedResourceInPendingDeleteProhibitsOperationException thrown =
@@ -1516,7 +1518,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
loadByForeignKey(Host.class, "ns2.example.foo", clock.nowUtc())
.get()
.asBuilder()
.addStatusValue(StatusValue.PENDING_DELETE)
.addStatusValue(PENDING_DELETE)
.build());
clock.advanceOneMilli();
LinkedResourceInPendingDeleteProhibitsOperationException thrown =
@@ -1681,9 +1683,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
persistReferencedEntities();
persistDomain();
doSuccessfulTest();
assertAboutDomains()
.that(reloadResourceByForeignKey())
.hasExactlyStatusValues(StatusValue.CLIENT_HOLD);
assertAboutDomains().that(reloadResourceByForeignKey()).hasExactlyStatusValues(CLIENT_HOLD);
}
@Test
@@ -1756,10 +1756,10 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
persistDomain()
.asBuilder()
.setDomainName("example.tld")
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_TRANSFER_PROHIBITED))
.setStatusValues(ImmutableSet.of(CLIENT_TRANSFER_PROHIBITED))
.build());
runFlowAsSuperuser();
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
}
@Test
@@ -1772,10 +1772,10 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
persistDomain()
.asBuilder()
.setDomainName("example.tld")
.setStatusValues(ImmutableSet.of(StatusValue.SERVER_HOLD))
.setStatusValues(ImmutableSet.of(SERVER_HOLD))
.build());
runFlowAsSuperuser();
dnsUtilsHelper.assertDomainDnsRequests("example.tld");
assertDomainDnsRequests("example.tld");
}
@Test
@@ -1788,9 +1788,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
persistDomain()
.asBuilder()
.setDomainName("example.tld")
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE, StatusValue.SERVER_HOLD))
.setStatusValues(ImmutableSet.of(PENDING_DELETE, SERVER_HOLD))
.build());
runFlowAsSuperuser();
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
}
@@ -16,7 +16,9 @@ package google.registry.flows.host;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.testing.DatabaseHelper.assertHostDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.newHost;
@@ -116,7 +118,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
void testSuccess_externalNeverExisted() throws Exception {
doSuccessfulTest();
assertAboutHosts().that(reloadResourceByForeignKey()).hasSuperordinateDomain(null);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -127,7 +129,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
loadByForeignKey(Domain.class, "example.tld", clock.nowUtc()).get();
assertAboutHosts().that(host).hasSuperordinateDomain(superordinateDomain.createVKey());
assertThat(superordinateDomain.getSubordinateHosts()).containsExactly("ns1.example.tld");
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld");
assertHostDnsRequests("ns1.example.tld");
}
@Test
@@ -144,7 +146,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
persistDeletedHost(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
doSuccessfulTest();
assertAboutHosts().that(reloadResourceByForeignKey()).hasSuperordinateDomain(null);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -156,7 +158,7 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
loadByForeignKey(Domain.class, "example.tld", clock.nowUtc()).get();
assertAboutHosts().that(host).hasSuperordinateDomain(superordinateDomain.createVKey());
assertThat(superordinateDomain.getSubordinateHosts()).containsExactly("ns1.example.tld");
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld");
assertHostDnsRequests("ns1.example.tld");
}
@Test
@@ -15,7 +15,9 @@
package google.registry.flows.host;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.assertHostDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadByKey;
import static google.registry.testing.DatabaseHelper.newHost;
@@ -314,10 +316,10 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Host> {
.hasType(Type.HOST_DELETE);
assertNoBillingEvents();
if (isSubordinate) {
dnsUtilsHelper.assertHostDnsRequests(deletedHost.getHostName());
assertHostDnsRequests(deletedHost.getHostName());
assertThat(loadByKey(deletedHost.getSuperordinateDomain()).getSubordinateHosts()).isEmpty();
} else {
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
assertLastHistoryContainsResource(deletedHost);
}
@@ -19,7 +19,9 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.dns.RefreshDnsOnHostRenameAction.PARAM_HOST_KEY;
import static google.registry.dns.RefreshDnsOnHostRenameAction.QUEUE_HOST_RENAME;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.testing.DatabaseHelper.assertHostDnsRequests;
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequests;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
import static google.registry.testing.DatabaseHelper.loadByEntity;
@@ -183,7 +185,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
Host renamedHost = doSuccessfulTest();
assertThat(renamedHost.isSubordinate()).isTrue();
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld", "ns2.example.tld");
assertHostDnsRequests("ns1.example.tld", "ns2.example.tld");
VKey<Host> oldVKeyAfterRename = ForeignKeyUtils.load(Host.class, oldHostName(), clock.nowUtc());
assertThat(oldVKeyAfterRename).isNull();
}
@@ -232,7 +234,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_UPDATE);
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld");
assertHostDnsRequests("ns1.example.tld");
}
@Test
@@ -258,7 +260,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_UPDATE);
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld");
assertHostDnsRequests("ns1.example.tld");
}
@Test
@@ -292,7 +294,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
.hasLastTransferTime(oneDayAgo);
Domain reloadedDomain = loadByEntity(domain).cloneProjectedAtTime(now);
assertThat(reloadedDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
dnsUtilsHelper.assertHostDnsRequests("ns1.example.tld", "ns2.example.tld");
assertHostDnsRequests("ns1.example.tld", "ns2.example.tld");
}
@Test
@@ -327,7 +329,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
assertThat(loadByEntity(foo).cloneProjectedAtTime(now).getSubordinateHosts()).isEmpty();
assertThat(loadByEntity(example).cloneProjectedAtTime(now).getSubordinateHosts())
.containsExactly("ns2.example.tld");
dnsUtilsHelper.assertHostDnsRequests("ns2.foo.tld", "ns2.example.tld");
assertHostDnsRequests("ns2.foo.tld", "ns2.example.tld");
}
@Test
@@ -364,7 +366,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
assertThat(reloadedFooDomain.getSubordinateHosts()).isEmpty();
Domain reloadedTldDomain = loadByEntity(tldDomain).cloneProjectedAtTime(now);
assertThat(reloadedTldDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
dnsUtilsHelper.assertHostDnsRequests("ns1.example.foo", "ns2.example.tld");
assertHostDnsRequests("ns1.example.foo", "ns2.example.tld");
}
@Test
@@ -407,7 +409,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
assertThat(renamedHost.getLastTransferTime()).isEqualTo(oneDayAgo);
Domain reloadedDomain = loadByEntity(domain).cloneProjectedAtTime(clock.nowUtc());
assertThat(reloadedDomain.getSubordinateHosts()).isEmpty();
dnsUtilsHelper.assertHostDnsRequests("ns1.example.foo");
assertHostDnsRequests("ns1.example.foo");
}
@Test
@@ -419,7 +421,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
persistActiveHost(oldHostName());
assertThat(domain.getSubordinateHosts()).isEmpty();
assertThrows(CannotRenameExternalHostException.class, this::runFlow);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -443,7 +445,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
.hasLastTransferTime(null);
assertThat(loadByEntity(domain).cloneProjectedAtTime(now).getSubordinateHosts())
.containsExactly("ns2.example.tld");
dnsUtilsHelper.assertHostDnsRequests("ns2.example.tld");
assertHostDnsRequests("ns2.example.tld");
}
@Test
@@ -468,7 +470,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
.hasPersistedCurrentSponsorRegistrarId("TheRegistrar")
.and()
.hasLastTransferTime(null);
dnsUtilsHelper.assertNoMoreDnsRequests();
assertNoDnsRequests();
}
@Test
@@ -22,7 +22,7 @@ import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableList;
import google.registry.dns.DnsConstants.TargetType;
import google.registry.dns.DnsUtils;
import google.registry.model.EntityTestCase;
import org.junit.jupiter.api.Test;
@@ -34,7 +34,8 @@ public class DnsRefreshRequestTest extends EntityTestCase {
}
private final DnsRefreshRequest request =
new DnsRefreshRequest(TargetType.DOMAIN, "test.example", "example", fakeClock.nowUtc());
new DnsRefreshRequest(
DnsUtils.TargetType.DOMAIN, "test.example", "example", fakeClock.nowUtc());
@Test
void testPersistence() {
@@ -56,15 +57,18 @@ public class DnsRefreshRequestTest extends EntityTestCase {
// name
assertThrows(
NullPointerException.class,
() -> new DnsRefreshRequest(TargetType.DOMAIN, null, "example", fakeClock.nowUtc()));
() ->
new DnsRefreshRequest(DnsUtils.TargetType.DOMAIN, null, "example", fakeClock.nowUtc()));
// tld
assertThrows(
NullPointerException.class,
() -> new DnsRefreshRequest(TargetType.DOMAIN, "test.example", null, fakeClock.nowUtc()));
() ->
new DnsRefreshRequest(
DnsUtils.TargetType.DOMAIN, "test.example", null, fakeClock.nowUtc()));
// request time
assertThrows(
NullPointerException.class,
() -> new DnsRefreshRequest(TargetType.DOMAIN, "test.example", "example", null));
() -> new DnsRefreshRequest(DnsUtils.TargetType.DOMAIN, "test.example", "example", null));
}
@Test
@@ -71,9 +71,6 @@ public final class RegistryTestServer {
route("/_dr/task/nordnUpload", BackendServlet.class),
route("/_dr/task/nordnVerify", BackendServlet.class),
// Process DNS pull queue
route("/_dr/cron/readDnsQueue", BackendServlet.class),
// Registrar Console
route("/registrar", FrontendServlet.class),
route("/registrar-create", FrontendServlet.class),
@@ -48,6 +48,7 @@ import google.registry.model.ImmutableObject;
import google.registry.util.Retrier;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
@@ -69,11 +70,6 @@ import org.joda.time.DateTime;
/**
* Static utility functions for testing task queues.
*
* <p>This class is mostly derived from {@link TaskQueueHelper}. It does not implement as many
* helper methods because we have not yet encountered all the use cases with Cloud Tasks. As more
* and more Task Queue API usage is migrated to Cloud Tasks we may replicate more methods from the
* latter.
*
* <p>Note the use of {@link AtomicInteger} {@code nextInstanceId} here. When a {@link
* FakeCloudTasksClient} instance, and by extension the {@link CloudTasksHelper} instance that
* contains it is serialized/deserialized, as happens in a Beam pipeline, we to want to push tasks
@@ -101,7 +97,7 @@ public class CloudTasksHelper implements Serializable {
private final CloudTasksUtils cloudTasksUtils;
public CloudTasksHelper(FakeClock clock) {
this.cloudTasksUtils =
cloudTasksUtils =
new CloudTasksUtils(
new Retrier(new FakeSleeper(clock), 1),
clock,
@@ -246,7 +242,7 @@ public class CloudTasksHelper implements Serializable {
new URI(
String.format(
"https://nomulus.foo%s", task.getAppEngineHttpRequest().getRelativeUri()));
} catch (java.net.URISyntaxException e) {
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
taskName = task.getName();
@@ -291,7 +287,7 @@ public class CloudTasksHelper implements Serializable {
builder.put("headers", headers);
builder.put("params", params);
builder.put("scheduleTime", scheduleTime);
return Maps.filterValues(builder, not(in(asList(null, "", Collections.EMPTY_MAP))));
return Maps.filterValues(builder, not(in(asList(null, "", Collections.emptyMap()))));
}
}
@@ -388,7 +384,7 @@ public class CloudTasksHelper implements Serializable {
.join(
Maps.transformValues(
expected.toMap(),
input -> "\t" + String.valueOf(input).replaceAll("\n", "\n\t")));
input -> '\t' + String.valueOf(input).replaceAll("\n", "\n\t")));
}
}
}
@@ -33,6 +33,7 @@ import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableO
import static google.registry.model.ImmutableObjectSubject.immutableObjectCorrespondence;
import static google.registry.model.ResourceTransferUtils.createTransferResponse;
import static google.registry.model.tld.Tld.TldState.GENERAL_AVAILABILITY;
import static google.registry.persistence.transaction.QueryComposer.Comparator.EQ;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import static google.registry.util.CollectionUtils.difference;
@@ -56,6 +57,8 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Iterables;
import com.google.common.net.InetAddresses;
import google.registry.dns.DnsUtils;
import google.registry.dns.DnsUtils.TargetType;
import google.registry.dns.writer.VoidDnsWriter;
import google.registry.model.Buildable;
import google.registry.model.EppResource;
@@ -70,6 +73,7 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingRecurrence;
import google.registry.model.common.DatabaseMigrationStateSchedule;
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
import google.registry.model.common.DnsRefreshRequest;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.contact.ContactHistory;
@@ -124,7 +128,7 @@ import org.joda.time.Duration;
/** Static utils for setting up test resources. */
public final class DatabaseHelper {
// If the clock is defined, it will always be advanced by one millsecond after a transaction.
// If the clock is defined, it will always be advanced by one millisecond after a transaction.
private static FakeClock clock;
private static final Supplier<String[]> DEFAULT_PREMIUM_LIST_CONTENTS =
@@ -1352,5 +1356,49 @@ public final class DatabaseHelper {
DatabaseMigrationStateSchedule.CACHE.invalidateAll();
}
private static ImmutableList<String> getDnsRefreshRequests(TargetType type, String... names) {
return tm().transact(
() ->
tm().createQueryComposer(DnsRefreshRequest.class).where("type", EQ, type).stream()
.map(DnsRefreshRequest::getName)
.filter(e -> ImmutableList.copyOf(names).contains(e))
.collect(toImmutableList()));
}
public static void assertDomainDnsRequests(String... domainNames) {
assertThat(getDnsRefreshRequests(DnsUtils.TargetType.DOMAIN, domainNames))
.containsExactlyElementsIn(domainNames);
}
public static void assertHostDnsRequests(String... hostNames) {
assertThat(getDnsRefreshRequests(DnsUtils.TargetType.HOST, hostNames))
.containsExactlyElementsIn(hostNames);
}
public static void assertNoDnsRequestsExcept(String... names) {
assertThat(
loadAllOf(DnsRefreshRequest.class).stream()
.filter(e -> !ImmutableList.copyOf(names).contains(e.getName()))
.count())
.isEqualTo(0);
}
public static void assertNoDnsRequests() {
assertNoDnsRequestsExcept();
}
public static void assertDomainDnsRequestWithRequestTime(
String domainName, DateTime requestTime) {
assertThat(
tm().transact(
() ->
tm().createQueryComposer(DnsRefreshRequest.class)
.where("type", EQ, DnsUtils.TargetType.DOMAIN)
.where("name", EQ, domainName)
.where("requestTime", EQ, requestTime)
.count()))
.isEqualTo(1);
}
private DatabaseHelper() {}
}
@@ -1,73 +0,0 @@
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.testing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import google.registry.dns.DnsUtils;
import google.registry.model.annotations.DeleteAfterMigration;
import org.joda.time.Duration;
/**
* Test helper for {@link DnsUtils}.
*
* <p>This is a temporary test class that is only used during DNS pull queue migration. Once we are
* no longer using the pull queue method, we can just assert on the inserted SQL entry instead in
* {@link DatabaseHelper}.
*/
@DeleteAfterMigration
public class DnsUtilsHelper {
private final DnsUtils dnsUtils;
public DnsUtilsHelper() {
dnsUtils = mock(DnsUtils.class);
}
public DnsUtilsHelper(DnsUtils dnsUtils) {
this.dnsUtils = dnsUtils;
}
public DnsUtils getDnsUtils() {
return dnsUtils;
}
public void assertDomainDnsRequests(String... domainNames) {
for (String domainName : domainNames) {
verify(dnsUtils).requestDomainDnsRefresh(domainName);
}
}
public void assertDomainDnsRequestWithDelay(String domainName, Duration delay) {
verify(dnsUtils).requestDomainDnsRefresh(domainName, delay);
}
public void assertNoDomainDnsRequestWithDelay(String domainName, Duration delay) {
verify(dnsUtils, never()).requestDomainDnsRefresh(domainName, delay);
}
public void assertHostDnsRequests(String... hostNames) {
for (String hostName : hostNames) {
verify(dnsUtils).requestHostDnsRefresh(hostName);
}
}
public void assertNoMoreDnsRequests() {
verifyNoMoreInteractions(dnsUtils);
}
}
@@ -1,61 +0,0 @@
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.testing;
import static com.google.common.io.Files.asCharSink;
import static google.registry.util.ResourceUtils.readResourceUtf8;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalTaskQueueTestConfig;
import com.google.apphosting.api.ApiProxy;
import google.registry.model.annotations.DeleteAfterMigration;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
/** JUnit extension that sets up App Engine task queue environment. */
@DeleteAfterMigration
public final class TaskQueueExtension implements BeforeEachCallback, AfterEachCallback {
/**
* The GAE testing library requires queue.xml to be a file, not a resource in a jar, so we read it
* in here and write it to a temporary file later.
*/
private static final String QUEUE_XML =
readResourceUtf8("google/registry/env/common/default/WEB-INF/queue.xml");
private LocalServiceTestHelper helper;
private Path queueFile;
@Override
public void beforeEach(ExtensionContext context) throws Exception {
queueFile = Files.createTempFile("queue", ".xml");
asCharSink(queueFile.toFile(), UTF_8).write(QUEUE_XML);
helper =
new LocalServiceTestHelper(
new LocalTaskQueueTestConfig().setQueueXmlPath(queueFile.toAbsolutePath().toString()));
helper.setUp();
}
@Override
public void afterEach(ExtensionContext context) throws Exception {
helper.tearDown();
Files.delete(queueFile);
ApiProxy.setEnvironmentForCurrentThread(null);
}
}
@@ -1,374 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.testing;
import static com.google.appengine.tools.development.testing.LocalTaskQueueTestConfig.getLocalTaskQueue;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.in;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.getFirst;
import static com.google.common.collect.Multisets.containsOccurrences;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.util.DiffUtils.prettyPrintEntityDeepDiff;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.joining;
import com.google.appengine.api.taskqueue.dev.QueueStateInfo;
import com.google.appengine.api.taskqueue.dev.QueueStateInfo.HeaderWrapper;
import com.google.appengine.api.taskqueue.dev.QueueStateInfo.TaskStateInfo;
import com.google.common.base.Ascii;
import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.net.HttpHeaders;
import com.google.common.net.MediaType;
import google.registry.dns.DnsConstants;
import google.registry.model.ImmutableObject;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import org.joda.time.Duration;
/** Static utility functions for testing task queues. */
public class TaskQueueHelper {
/**
* Matcher to match against the tasks in the task queue. Fields that aren't set are not compared.
*/
public static class TaskMatcher implements Predicate<TaskStateInfo> {
private final MatchableTaskInfo expected;
public TaskMatcher() {
expected = new MatchableTaskInfo();
}
/**
* Constructor to create a TaskMatcher that should exactly match an existing TaskStateInfo.
*
* This is useful for checking that a pre-existing task as returned by TaskStateInfo is still
* in the queue; we can't just directly compare the lists of TaskStateInfos because they have
* no equals() override and there's no guarantee that reference equality is sufficient.
*/
private TaskMatcher(TaskStateInfo taskStateInfo) {
expected = new MatchableTaskInfo(taskStateInfo);
}
public TaskMatcher taskName(String taskName) {
expected.taskName = taskName;
return this;
}
public TaskMatcher url(String url) {
expected.url = url;
return this;
}
/**
* Sets the HTTP method to match against. WARNING: due to b/38459667, pull queue tasks will
* report "POST" as their method.
*/
public TaskMatcher method(String method) {
expected.method = method;
return this;
}
public TaskMatcher payload(String payload) {
checkState(expected.params.isEmpty(), "Cannot add a payload to a TaskMatcher with params");
expected.payload = payload;
return this;
}
public TaskMatcher tag(String tag) {
expected.tag = tag;
return this;
}
public TaskMatcher header(String name, String value) {
// Lowercase for case-insensitive comparison.
expected.headers.put(Ascii.toLowerCase(name), value);
return this;
}
public TaskMatcher param(String key, String value) {
checkState(expected.payload == null, "Cannot add params to a TaskMatcher with a payload");
checkNotNull(value, "Test error: A task can never have a null value, so don't assert it");
expected.params.put(key, value);
return this;
}
public TaskMatcher etaDelta(Duration lowerBound, Duration upperBound) {
checkState(!lowerBound.isShorterThan(Duration.ZERO), "lowerBound must be non-negative");
checkState(
upperBound.isLongerThan(lowerBound), "upperBound must be greater than lowerBound");
expected.etaDeltaLowerBound = lowerBound.getStandardSeconds();
expected.etaDeltaUpperBound = upperBound.getStandardSeconds();
return this;
}
/**
* Returns {@code true} if there are not more occurrences in {@code sub} of each of its entries
* than there are in {@code super}.
*/
private static boolean containsEntries(
Multimap<?, ?> superMultimap, Multimap<?, ?> subMultimap) {
return containsOccurrences(
ImmutableMultiset.copyOf(superMultimap.entries()),
ImmutableMultiset.copyOf(subMultimap.entries()));
}
/**
* Returns true if the fields set on the current object match the given task info. This is not
* quite the same contract as {@link #equals}, since it will ignore null fields.
*
* <p>Match fails if any headers or params expected on the TaskMatcher are not found on the
* TaskStateInfo. Note that the inverse is not true (i.e. there may be extra headers on the
* TaskStateInfo).
*/
@Override
public boolean test(@Nonnull TaskStateInfo info) {
MatchableTaskInfo actual = new MatchableTaskInfo(info);
return (expected.taskName == null || Objects.equals(expected.taskName, actual.taskName))
&& (expected.url == null || Objects.equals(expected.url, actual.url))
&& (expected.method == null || Objects.equals(expected.method, actual.method))
&& (expected.payload == null || Objects.equals(expected.payload, actual.payload))
&& (expected.tag == null || Objects.equals(expected.tag, actual.tag))
&& (expected.etaDeltaLowerBound == null
|| expected.etaDeltaLowerBound <= actual.etaDelta)
&& (expected.etaDeltaUpperBound == null
|| expected.etaDeltaUpperBound >= actual.etaDelta)
&& containsEntries(actual.params, expected.params)
&& containsEntries(actual.headers, expected.headers);
}
@Override
public String toString() {
return Joiner.on('\n')
.withKeyValueSeparator(":\n")
.join(
Maps.transformValues(
expected.toMap(),
input -> "\t" + String.valueOf(input).replaceAll("\n", "\n\t")));
}
}
/** Returns the info object for the provided queue name. */
public static QueueStateInfo getQueueInfo(String queueName) {
return getLocalTaskQueue().getQueueStateInfo().get(queueName);
}
/**
* Ensures that the tasks in the named queue are exactly those with the expected property
* values after being transformed with the provided property getter function.
*/
public static void assertTasksEnqueuedWithProperty(
String queueName,
Function<TaskStateInfo, String> propertyGetter,
String... expectedTaskProperties) {
// Ordering is irrelevant but duplicates should be considered independently.
assertThat(getQueueInfo(queueName).getTaskInfo().stream().map(propertyGetter))
.containsExactly((Object[]) expectedTaskProperties);
}
/** Ensures that the tasks in the named queue are exactly those with the expected names. */
public static void assertTasksEnqueued(String queueName, String... expectedTaskNames) {
Function<TaskStateInfo, String> nameGetter = TaskStateInfo::getTaskName;
assertTasksEnqueuedWithProperty(queueName, nameGetter, expectedTaskNames);
}
public static void assertTasksEnqueued(String queueName, Iterable<TaskStateInfo> taskStateInfos) {
ImmutableList.Builder<TaskMatcher> taskMatchers = new ImmutableList.Builder<>();
for (TaskStateInfo taskStateInfo : taskStateInfos) {
taskMatchers.add(new TaskMatcher(taskStateInfo));
}
assertTasksEnqueued(queueName, taskMatchers.build());
}
/**
* Ensures that the only tasks in the named queue are exactly those that match the expected
* matchers.
*/
public static void assertTasksEnqueued(String queueName, TaskMatcher... taskMatchers) {
assertTasksEnqueued(queueName, Arrays.asList(taskMatchers));
}
/**
* Ensures that the only tasks in the named queue are exactly those that match the expected
* matchers.
*/
public static void assertTasksEnqueued(String queueName, Collection<TaskMatcher> taskMatchers) {
QueueStateInfo qsi = getQueueInfo(queueName);
assertThat(qsi.getTaskInfo()).hasSize(taskMatchers.size());
List<TaskStateInfo> taskInfos = new ArrayList<>(qsi.getTaskInfo());
for (final TaskMatcher taskMatcher : taskMatchers) {
try {
taskInfos.remove(taskInfos.stream().filter(taskMatcher).findFirst().get());
} catch (NoSuchElementException e) {
final Map<String, Object> taskMatcherMap = taskMatcher.expected.toMap();
assertWithMessage(
"Task not found in queue %s:\n\n%s\n\nPotential candidate match diffs:\n\n%s",
queueName,
taskMatcher,
taskInfos.stream()
.map(
input ->
prettyPrintEntityDeepDiff(
taskMatcherMap,
Maps.filterKeys(
new MatchableTaskInfo(input).toMap(),
in(taskMatcherMap.keySet()))))
.collect(joining("\n")))
.fail();
}
}
}
public static ImmutableList<ImmutableMultimap<String, String>> getQueuedParams(String queueName) {
return getQueueInfo(queueName)
.getTaskInfo()
.stream()
.map(MatchableTaskInfo::new)
.map(taskInfo -> ImmutableMultimap.copyOf(taskInfo.params))
.collect(toImmutableList());
}
/** Empties the task queue. */
public static void clearTaskQueue(String queueName) {
getLocalTaskQueue().flushQueue(queueName);
}
/** Asserts at least one task exists in {@code queue}. */
public static void assertAtLeastOneTaskIsEnqueued(String queue) {
assertThat(getQueueInfo(queue).getCountTasks()).isGreaterThan(0);
}
/** Ensures that the named queue contains no tasks. */
public static void assertNoTasksEnqueued(String ... queueNames) {
for (String queueName : queueNames) {
assertThat(getQueueInfo(queueName).getCountTasks()).isEqualTo(0);
}
}
/** Returns the value for the param on a task info, or empty if it is missing. */
private static String getParamFromTaskInfo(TaskStateInfo taskInfo, String paramName) {
return getFirst(UriParameters.parse(taskInfo.getBody()).get(paramName), "");
}
/** Ensures that the DNS queue tasks are exactly those for the expected target names. */
public static void assertDnsTasksEnqueued(String... expectedTaskTargetNames) {
assertTasksEnqueuedWithProperty(
DnsConstants.DNS_PULL_QUEUE_NAME,
taskStateInfo -> getParamFromTaskInfo(taskStateInfo, DnsConstants.DNS_TARGET_NAME_PARAM),
expectedTaskTargetNames);
}
/** Ensures that the DNS queue does not contain any tasks. */
public static void assertNoDnsTasksEnqueued() {
assertNoTasksEnqueued(DnsConstants.DNS_PULL_QUEUE_NAME);
}
/** An adapter to clean up a {@link TaskStateInfo} for ease of matching. */
private static class MatchableTaskInfo extends ImmutableObject {
String taskName;
String method;
String url;
String payload;
String tag;
Double etaDelta;
Long etaDeltaLowerBound;
Long etaDeltaUpperBound;
Multimap<String, String> headers = ArrayListMultimap.create();
Multimap<String, String> params = ArrayListMultimap.create();
MatchableTaskInfo() {}
MatchableTaskInfo(TaskStateInfo info) {
URI uri;
try {
uri = new URI(info.getUrl());
} catch (java.net.URISyntaxException e) {
throw new IllegalArgumentException(e);
}
this.taskName = info.getTaskName();
this.method = info.getMethod();
this.url = uri.getPath();
this.payload = info.getBody();
this.etaDelta = info.getEtaDelta();
if (info.getTagAsBytes() != null) {
this.tag = new String(info.getTagAsBytes(), UTF_8);
}
ImmutableMultimap.Builder<String, String> headerBuilder = new ImmutableMultimap.Builder<>();
for (HeaderWrapper header : info.getHeaders()) {
// Lowercase header name for comparison since HTTP
// header names are case-insensitive.
headerBuilder.put(Ascii.toLowerCase(header.getKey()), header.getValue());
}
this.headers = headerBuilder.build();
ImmutableMultimap.Builder<String, String> inputParams = new ImmutableMultimap.Builder<>();
String query = uri.getQuery();
if (query != null) {
inputParams.putAll(UriParameters.parse(query));
}
boolean hasFormDataContentType =
headers.containsEntry(
Ascii.toLowerCase(HttpHeaders.CONTENT_TYPE), MediaType.FORM_DATA.toString());
// Try decoding the body as a parameter map if it either has the "x-www-form-urlencoded"
// content type, or if it's a POST or PULL task (in which case parameters should be encoded
// into the body automatically upon being enqueued). Note that pull queue tasks also report
// "POST" as their method (which is misleading - see b/38459667) so we just check for "POST".
if (hasFormDataContentType || "POST".equals(this.method)) {
// Note that UriParameters.parse() does not throw an IAE on a bad query string (e.g. one
// where parameters are not properly URL-encoded); it always does a best-effort parse.
inputParams.putAll(UriParameters.parse(info.getBody()));
}
this.params = inputParams.build();
}
public Map<String, Object> toMap() {
Map<String, Object> builder = new HashMap<>();
builder.put("taskName", taskName);
builder.put("url", url);
builder.put("method", method);
builder.put("headers", headers.asMap());
builder.put("params", params.asMap());
builder.put("payload", payload);
builder.put("tag", tag);
builder.put("etaDelta", etaDelta);
builder.put("etaDeltaLowerBound", etaDeltaLowerBound);
builder.put("etaDeltaUpperBound", etaDeltaUpperBound);
return Maps.filterValues(builder, not(in(asList(null, "", Collections.EMPTY_MAP))));
}
}
}
@@ -15,27 +15,20 @@
package google.registry.tools.server;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.assertDomainDnsRequestWithRequestTime;
import static google.registry.testing.DatabaseHelper.assertNoDnsRequestsExcept;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import com.google.common.collect.ImmutableSet;
import google.registry.dns.DnsUtils;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.DnsUtilsHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import java.util.Random;
import org.apache.http.HttpStatus;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -44,14 +37,12 @@ import org.junit.jupiter.api.extension.RegisterExtension;
public class RefreshDnsForAllDomainsActionTest {
private final FakeClock clock = new FakeClock(DateTime.parse("2020-02-02T02:02:02Z"));
private final DnsUtils dnsUtils = mock(DnsUtils.class);
private final DnsUtilsHelper dnsUtilsHelper = new DnsUtilsHelper(dnsUtils);
private RefreshDnsForAllDomainsAction action;
private final FakeResponse response = new FakeResponse();
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@BeforeEach
void beforeEach() {
@@ -60,37 +51,18 @@ public class RefreshDnsForAllDomainsActionTest {
action.random = new Random();
action.random.setSeed(123L);
action.clock = clock;
action.dnsUtils = dnsUtils;
action.response = response;
createTld("bar");
}
@Test
void test_runAction_errorRequestDnsRefresh() throws Exception {
persistActiveDomain("foo.bar");
persistActiveDomain("baz.bar");
persistActiveDomain("low.bar");
action.tlds = ImmutableSet.of("bar");
doThrow(new RuntimeException("Error enqueuing task."))
.when(dnsUtils)
.requestDomainDnsRefresh(eq("baz.bar"), any(Duration.class));
action.run();
dnsUtilsHelper.assertDomainDnsRequestWithDelay("low.bar", Duration.ZERO);
dnsUtilsHelper.assertDomainDnsRequestWithDelay("baz.bar", Duration.ZERO);
dnsUtilsHelper.assertDomainDnsRequestWithDelay("foo.bar", Duration.ZERO);
verifyNoMoreInteractions(dnsUtils);
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_INTERNAL_SERVER_ERROR);
}
@Test
void test_runAction_successfullyEnqueuesDnsRefreshes() throws Exception {
persistActiveDomain("foo.bar");
persistActiveDomain("low.bar");
action.tlds = ImmutableSet.of("bar");
action.run();
dnsUtilsHelper.assertDomainDnsRequestWithDelay("foo.bar", Duration.ZERO);
dnsUtilsHelper.assertDomainDnsRequestWithDelay("low.bar", Duration.ZERO);
assertDomainDnsRequestWithRequestTime("foo.bar", clock.nowUtc());
assertDomainDnsRequestWithRequestTime("low.bar", clock.nowUtc());
}
@Test
@@ -100,8 +72,8 @@ public class RefreshDnsForAllDomainsActionTest {
action.tlds = ImmutableSet.of("bar");
action.smearMinutes = 1000;
action.run();
dnsUtilsHelper.assertDomainDnsRequestWithDelay("foo.bar", Duration.standardMinutes(450));
dnsUtilsHelper.assertDomainDnsRequestWithDelay("low.bar", Duration.standardMinutes(782));
assertDomainDnsRequestWithRequestTime("foo.bar", clock.nowUtc().plusMinutes(450));
assertDomainDnsRequestWithRequestTime("low.bar", clock.nowUtc().plusMinutes(782));
}
@Test
@@ -110,8 +82,8 @@ public class RefreshDnsForAllDomainsActionTest {
persistDeletedDomain("deleted.bar", clock.nowUtc().minusYears(1));
action.tlds = ImmutableSet.of("bar");
action.run();
dnsUtilsHelper.assertDomainDnsRequestWithDelay("foo.bar", Duration.ZERO);
dnsUtilsHelper.assertNoDomainDnsRequestWithDelay("deleted.bar", Duration.ZERO);
assertDomainDnsRequestWithRequestTime("foo.bar", clock.nowUtc());
assertNoDnsRequestsExcept("foo.bar");
}
@Test
@@ -122,9 +94,9 @@ public class RefreshDnsForAllDomainsActionTest {
persistActiveDomain("ignore.baz");
action.tlds = ImmutableSet.of("bar");
action.run();
dnsUtilsHelper.assertDomainDnsRequestWithDelay("foo.bar", Duration.ZERO);
dnsUtilsHelper.assertDomainDnsRequestWithDelay("low.bar", Duration.ZERO);
dnsUtilsHelper.assertNoDomainDnsRequestWithDelay("ignore.baz", Duration.ZERO);
assertDomainDnsRequestWithRequestTime("foo.bar", clock.nowUtc());
assertDomainDnsRequestWithRequestTime("low.bar", clock.nowUtc());
assertNoDnsRequestsExcept("foo.bar", "low.bar");
}
@Test
@@ -1,6 +1,5 @@
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
/_dr/cron/fanout TldFanoutAction GET y INTERNAL,API APP ADMIN
/_dr/cron/readDnsQueue ReadDnsQueueAction GET y INTERNAL,API APP ADMIN
/_dr/dnsRefresh RefreshDnsAction GET y INTERNAL,API APP ADMIN
/_dr/task/brdaCopy BrdaCopyAction POST y INTERNAL,API APP ADMIN
/_dr/task/copyDetailReports CopyDetailReportsAction POST n INTERNAL,API APP ADMIN