Partially convert EppResourceUtils to SQL (#1060)

* Partially convert EppResourceUtils to SQL

Some of the rest will depend on b/184578521.

The primary conversion in this PR is the change in
NameserverLookupByIpCommand as that is the only place where the removed
EppResourceUtils method was called. We also convert to DualDatabaseTest
the tests of the callers of NLBIC. and use a CriteriaQueryBuilder in the
foreign key index SQL lookup (allowing us to avoid the String.format
call).
This commit is contained in:
gbrodman 2021-04-07 19:20:13 -04:00 committed by GitHub
parent da6d90755e
commit 0b520f3885
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 194 additions and 190 deletions

View file

@ -194,30 +194,6 @@ public final class EppResourceUtils {
return ForeignKeyIndex.load(clazz, uniqueIds, now).keySet();
}
/**
* Loads resources that match some filter and that have {@link EppResource#deletionTime} that is
* not before "now".
*
* <p>This is an eventually consistent query.
*
* @param clazz the resource type to load
* @param now the logical time of the check
* @param filterDefinition the filter to apply when loading resources
* @param filterValue the acceptable value for the filter
*/
public static <T extends EppResource> Iterable<T> queryNotDeleted(
Class<T> clazz, DateTime now, String filterDefinition, Object filterValue) {
return ofy()
.load()
.type(clazz)
.filter(filterDefinition, filterValue)
.filter("deletionTime >", now.toDate())
.list()
.stream()
.map(EppResourceUtils.transformAtTime(now))
.collect(toImmutableSet());
}
/**
* Returns a Function that transforms an EppResource to the given DateTime, suitable for use with
* Iterables.transform() over a collection of EppResources.

View file

@ -48,8 +48,10 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.CriteriaQueryBuilder;
import google.registry.schema.replay.DatastoreOnlyEntity;
import google.registry.util.NonFinalForTesting;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
@ -193,7 +195,7 @@ public abstract class ForeignKeyIndex<E extends EppResource> extends BackupGroup
* has been soft deleted.
*/
public static <E extends EppResource> ImmutableMap<String, ForeignKeyIndex<E>> load(
Class<E> clazz, Iterable<String> foreignKeys, final DateTime now) {
Class<E> clazz, Collection<String> foreignKeys, final DateTime now) {
return loadIndexesFromStore(clazz, foreignKeys).entrySet().stream()
.filter(e -> now.isBefore(e.getValue().getDeletionTime()))
.collect(entriesToImmutableMap());
@ -207,7 +209,7 @@ public abstract class ForeignKeyIndex<E extends EppResource> extends BackupGroup
*/
private static <E extends EppResource>
ImmutableMap<String, ForeignKeyIndex<E>> loadIndexesFromStore(
Class<E> clazz, Iterable<String> foreignKeys) {
Class<E> clazz, Collection<String> foreignKeys) {
if (tm().isOfy()) {
return ImmutableMap.copyOf(
tm().doTransactionless(() -> ofy().load().type(mapToFkiClass(clazz)).ids(foreignKeys)));
@ -215,19 +217,16 @@ public abstract class ForeignKeyIndex<E extends EppResource> extends BackupGroup
String property = RESOURCE_CLASS_TO_FKI_PROPERTY.get(clazz);
ImmutableList<ForeignKeyIndex<E>> indexes =
tm().transact(
() -> {
String entityName =
jpaTm().getEntityManager().getMetamodel().entity(clazz).getName();
return jpaTm()
.query(
String.format(
"FROM %s WHERE %s IN :propertyValue", entityName, property),
clazz)
.setParameter("propertyValue", foreignKeys)
() ->
jpaTm()
.getEntityManager()
.createQuery(
CriteriaQueryBuilder.create(clazz)
.whereFieldIsIn(property, foreignKeys)
.build())
.getResultStream()
.map(e -> ForeignKeyIndex.create(e, e.getDeletionTime()))
.collect(toImmutableList());
});
.collect(toImmutableList()));
// We need to find and return the entities with the maximum deletionTime for each foreign key.
return Multimaps.index(indexes, ForeignKeyIndex::getForeignKey).asMap().entrySet().stream()
.map(
@ -318,7 +317,7 @@ public abstract class ForeignKeyIndex<E extends EppResource> extends BackupGroup
* reasons, and are OK with the trade-offs in loss of transactional consistency.
*/
public static <E extends EppResource> ImmutableMap<String, ForeignKeyIndex<E>> loadCached(
Class<E> clazz, Iterable<String> foreignKeys, final DateTime now) {
Class<E> clazz, Collection<String> foreignKeys, final DateTime now) {
if (!RegistryConfig.isEppResourceCachingEnabled()) {
return tm().doTransactionless(() -> load(clazz, foreignKeys, now));
}

View file

@ -16,12 +16,15 @@ package google.registry.whois;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.model.EppResourceUtils.queryNotDeleted;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import com.google.common.net.InetAddresses;
import com.google.common.net.InternetDomainName;
import google.registry.model.host.HostResource;
import google.registry.model.registry.Registries;
@ -46,9 +49,34 @@ final class NameserverLookupByIpCommand implements WhoisCommand {
}
@Override
@SuppressWarnings("unchecked")
public WhoisResponse executeQuery(DateTime now) throws WhoisException {
Iterable<HostResource> hostsFromDb;
if (tm().isOfy()) {
hostsFromDb =
ofy()
.load()
.type(HostResource.class)
.filter("inetAddresses", ipAddress)
.filter("deletionTime >", now.toDate());
} else {
hostsFromDb =
jpaTm()
.transact(
() ->
// We cannot query @Convert-ed fields in HQL so we must use native Postgres
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT * From \"Host\" WHERE :address = ANY(inet_addresses) AND "
+ "deletion_time > CAST(:now AS timestamptz)",
HostResource.class)
.setParameter("address", InetAddresses.toAddrString(ipAddress))
.setParameter("now", now.toString())
.getResultList());
}
ImmutableList<HostResource> hosts =
Streams.stream(queryNotDeleted(HostResource.class, now, "inetAddresses", ipAddress))
Streams.stream(hostsFromDb)
.filter(
host ->
Registries.findTldForName(InternetDomainName.from(host.getHostName()))

View file

@ -218,27 +218,20 @@ public final class FullFieldsTestEntityHelper {
.setCountryCode("US")
.build());
}
ContactResource.Builder builder = new ContactResource.Builder()
ContactResource.Builder builder =
new ContactResource.Builder()
.setContactId(id)
.setRepoId(generateNewContactHostRoid())
.setCreationTimeForTest(DateTime.parse("2000-10-08T00:45:00Z"))
.setInternationalizedPostalInfo(postalBuilder.build())
.setVoiceNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.2126660420")
.build())
.setFaxNumber(
new ContactPhoneNumber.Builder()
.setPhoneNumber("+1.2126660420")
.build());
new ContactPhoneNumber.Builder().setPhoneNumber("+1.2126660420").build())
.setFaxNumber(new ContactPhoneNumber.Builder().setPhoneNumber("+1.2126660420").build());
if (email != null) {
builder.setEmailAddress(email);
}
if (registrar != null) {
builder
.setCreationClientId(registrar.getClientId())
.setPersistedCurrentSponsorClientId(registrar.getClientId());
}
String registrarId = registrar == null ? "TheRegistrar" : registrar.getClientId();
builder.setCreationClientId(registrarId).setPersistedCurrentSponsorClientId(registrarId);
if (deletionTime != null) {
builder.setDeletionTime(deletionTime);
}

View file

@ -54,11 +54,13 @@ import google.registry.model.registry.Registry;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.FakeSleeper;
import google.registry.testing.InjectExtension;
import google.registry.testing.TestCacheExtension;
import google.registry.testing.TestOfyAndSql;
import google.registry.util.Retrier;
import google.registry.whois.WhoisMetrics.WhoisMetric;
import java.io.IOException;
@ -68,15 +70,17 @@ import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link WhoisAction}. */
@DualDatabaseTest
public class WhoisActionTest {
private final FakeClock clock = new FakeClock(DateTime.parse("2009-06-29T20:13:00Z"));
@RegisterExtension
public final AppEngineExtension appEngine =
AppEngineExtension.builder().withDatastoreAndCloudSql().build();
AppEngineExtension.builder().withDatastoreAndCloudSql().withClock(clock).build();
@RegisterExtension public final InjectExtension inject = new InjectExtension();
@ -88,7 +92,6 @@ public class WhoisActionTest {
.build();
private final FakeResponse response = new FakeResponse();
private FakeClock clock;
private WhoisAction newWhoisAction(String input) {
WhoisAction whoisAction = new WhoisAction();
@ -107,12 +110,11 @@ public class WhoisActionTest {
@BeforeEach
void setUp() {
clock = new FakeClock(DateTime.parse("2009-06-29T20:13:00Z"));
createTlds("lol", "xn--q9jyb4c", "1.test");
inject.setStaticField(Ofy.class, "clock", clock);
}
@Test
@TestOfyAndSql
void testRun_badRequest_stillSends200() {
newWhoisAction("\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
@ -130,7 +132,7 @@ public class WhoisActionTest {
registrar);
}
@Test
@TestOfyAndSql
void testRun_domainQuery_works() {
Registrar registrar =
persistResource(makeRegistrar("evilregistrar", "Yes Virginia", ACTIVE));
@ -141,7 +143,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain.txt"));
}
@Test
@TestOfyAndSql
void testRun_domainQuery_usesCache() {
Registrar registrar =
persistResource(makeRegistrar("evilregistrar", "Yes Virginia", ACTIVE));
@ -169,7 +171,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain.txt"));
}
@Test
@TestOfyAndSql
void testRun_domainAfterTransfer_hasUpdatedEppTimeAndClientId() {
Registrar registrar = persistResource(makeRegistrar("TheRegistrar", "Yes Virginia", ACTIVE));
persistResource(
@ -194,7 +196,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_transferred_domain.txt"));
}
@Test
@TestOfyAndSql
void testRun_idnDomain_works() {
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", ACTIVE));
@ -212,7 +214,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_idn_punycode.txt"));
}
@Test
@TestOfyAndSql
void testRun_punycodeDomain_works() {
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", ACTIVE));
@ -230,14 +232,14 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_idn_punycode.txt"));
}
@Test
@TestOfyAndSql
void testRun_domainNotFound_returns200OkAndPlainTextResponse() {
newWhoisAction("domain cat.lol\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_domainNotFound_usesCache() {
// Populate the cache with the nonexistence of this domain.
assertThat(loadByForeignKeyCached(DomainBase.class, "cat.lol", clock.nowUtc())).isEmpty();
@ -250,7 +252,7 @@ public class WhoisActionTest {
// todo (b/27378695): reenable or delete this test
@Disabled
@Test
@TestOfyAndSql
void testRun_domainInTestTld_isConsideredNotFound() {
persistResource(Registry.get("lol").asBuilder().setTldType(Registry.TldType.TEST).build());
Registrar registrar = persistResource(makeRegistrar(
@ -269,7 +271,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_domainFlaggedAsDeletedInDatastore_isConsideredNotFound() {
Registrar registrar;
persistResource(makeDomainBase("cat.lol",
@ -294,7 +296,7 @@ public class WhoisActionTest {
* Create a deleted domain and an active domain with the same label, and make sure only the active
* one is returned.
*/
@Test
@TestOfyAndSql
void testRun_domainDeletedThenRecreated_isFound() {
Registrar registrar;
DomainBase domain1 = persistResource(makeDomainBase("cat.lol",
@ -330,7 +332,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("ns1.google.lol");
}
@Test
@TestOfyAndSql
void testRun_nameserverQuery_works() {
persistResource(loadRegistrar("TheRegistrar").asBuilder().setUrl("http://my.fake.url").build());
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
@ -339,7 +341,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver.txt"));
}
@Test
@TestOfyAndSql
void testRun_ipv6_displaysInCollapsedReadableFormat() {
persistResource(makeHostResource("ns1.cat.lol", "bad:f00d:cafe::15:beef"));
newWhoisAction("nameserver ns1.cat.lol\r\n").run();
@ -350,7 +352,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).doesNotContain("bad:f00d:cafe:0:0:0:15:beef");
}
@Test
@TestOfyAndSql
void testRun_idnNameserver_works() {
persistResource(makeHostResource("ns1.cat.みんな", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.みんな\r\n").run();
@ -359,7 +361,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
@TestOfyAndSql
void testRun_nameserver_usesCache() {
persistResource(makeHostResource("ns1.cat.xn--q9jyb4c", "1.2.3.4"));
// Populate the cache.
@ -376,7 +378,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
@TestOfyAndSql
void testRun_punycodeNameserver_works() {
persistResource(makeHostResource("ns1.cat.みんな", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.xn--q9jyb4c\r\n").run();
@ -385,7 +387,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
@TestOfyAndSql
void testRun_nameserverNotFound_returns200AndText() {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.lulz\r\n").run();
@ -393,7 +395,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_nameserverFlaggedAsDeletedInDatastore_doesntGetLeaked() {
persistResource(
makeHostResource("ns1.cat.lol", "1.2.3.4").asBuilder()
@ -403,7 +405,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_ipNameserverLookup_works() {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
newWhoisAction("nameserver 1.2.3.4").run();
@ -411,7 +413,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("ns1.cat.lol");
}
@Test
@TestOfyAndSql
void testRun_ipMapsToMultipleNameservers_theyAllGetReturned() {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
persistResource(makeHostResource("ns2.cat.lol", "1.2.3.4"));
@ -421,7 +423,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("ns2.cat.lol");
}
@Test
@TestOfyAndSql
void testRun_ipMapsToMultipleNameserverInDifferentTlds_showsThemAll() {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
persistResource(
@ -432,14 +434,14 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("ns1.cat.xn--q9jyb4c");
}
@Test
@TestOfyAndSql
void testRun_ipNameserverEntityDoesNotExist_returns200NotFound() {
newWhoisAction("nameserver feed:a:bee::acab\r\n").run();
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_ip_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_ipMapsToNameserverUnderNonAuthoritativeTld_notFound() {
assertThat(getTlds()).doesNotContain("com");
persistResource(makeHostResource("ns1.google.com", "1.2.3.4"));
@ -448,7 +450,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_ip_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_nameserverUnderNonAuthoritativeTld_notFound() {
assertThat(getTlds()).doesNotContain("com");
persistResource(makeHostResource("ns1.google.com", "1.2.3.4"));
@ -459,7 +461,7 @@ public class WhoisActionTest {
// todo (b/27378695): reenable or delete this test
@Disabled
@Test
@TestOfyAndSql
void testRun_nameserverInTestTld_notFound() {
persistResource(Registry.get("lol").asBuilder().setTldType(Registry.TldType.TEST).build());
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
@ -468,7 +470,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_registrarLookup_works() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", ACTIVE));
@ -479,7 +481,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar.txt"));
}
@Test
@TestOfyAndSql
void testRun_pdtRegistrarLookup_works() {
Registrar registrar =
persistResource(
@ -495,7 +497,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar.txt"));
}
@Test
@TestOfyAndSql
void testRun_registrarLookupInPendingState_returnsNotFound() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", Registrar.State.PENDING));
@ -505,7 +507,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_registrarLookupWithTestType_returnsNotFound() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", ACTIVE)
@ -519,7 +521,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_multilevelDomain_isNotConsideredAHostname() {
Registrar registrar =
persistResource(makeRegistrar("example", "Example Registrar", ACTIVE));
@ -537,7 +539,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("Domain Name: cat.1.test\r\n");
}
@Test
@TestOfyAndSql
void testRun_hostnameWithMultilevelTld_isStillConsideredHostname() {
persistResource(makeHostResource("ns1.cat.1.test", "1.2.3.4"));
newWhoisAction("nameserver ns1.cat.1.test\r\n").run();
@ -546,7 +548,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
@TestOfyAndSql
void testRun_metricsLoggedForSuccessfulCommand() {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
persistResource(makeHostResource("ns2.cat.lol", "1.2.3.4"));
@ -562,7 +564,7 @@ public class WhoisActionTest {
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
@Test
@TestOfyAndSql
void testRun_metricsLoggedForUnsuccessfulCommand() {
WhoisAction action = newWhoisAction("domain cat.lol\r\n");
action.whoisMetrics = mock(WhoisMetrics.class);
@ -576,7 +578,7 @@ public class WhoisActionTest {
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
@Test
@TestOfyAndSql
void testRun_metricsLoggedForInternalServerError() throws Exception {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
WhoisAction action = newWhoisAction("ns1.cat.lol");
@ -595,7 +597,7 @@ public class WhoisActionTest {
assertThat(response.getPayload()).isEqualTo("Internal Server Error");
}
@Test
@TestOfyAndSql
void testRun_retryOnTransientFailure() throws Exception {
persistResource(loadRegistrar("TheRegistrar").asBuilder().setUrl("http://my.fake.url").build());
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));

View file

@ -29,15 +29,17 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource;
import google.registry.model.registrar.Registrar;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.FakeClock;
import google.registry.testing.TestCacheExtension;
import google.registry.testing.TestOfyAndSql;
import java.net.InetAddress;
import org.joda.time.Duration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@DualDatabaseTest
class WhoisCommandFactoryTest {
FakeClock clock = new FakeClock();
@ -90,7 +92,7 @@ class WhoisCommandFactoryTest {
RegistryConfig.CONFIG_SETTINGS.get().caching.singletonCacheRefreshSeconds = 0;
}
@Test
@TestOfyAndSql
void testNonCached_NameserverLookupByHostCommand() throws Exception {
WhoisResponse response =
noncachedFactory
@ -114,7 +116,7 @@ class WhoisCommandFactoryTest {
.contains("Registrar: OtherRegistrar name");
}
@Test
@TestOfyAndSql
void testCached_NameserverLookupByHostCommand() throws Exception {
WhoisResponse response =
cachedFactory
@ -137,7 +139,7 @@ class WhoisCommandFactoryTest {
.contains("Registrar: The Registrar");
}
@Test
@TestOfyAndSql
void testNonCached_DomainLookupCommand() throws Exception {
WhoisResponse response =
noncachedFactory
@ -161,7 +163,7 @@ class WhoisCommandFactoryTest {
.contains("Registrar: OtherRegistrar name");
}
@Test
@TestOfyAndSql
void testCached_DomainLookupCommand() throws Exception {
WhoisResponse response =
cachedFactory
@ -185,7 +187,7 @@ class WhoisCommandFactoryTest {
.contains("Registrar: The Registrar");
}
@Test
@TestOfyAndSql
void testNonCached_RegistrarLookupCommand() throws Exception {
WhoisResponse response =
noncachedFactory.registrarLookup("OtherRegistrar").executeQuery(clock.nowUtc());
@ -199,7 +201,7 @@ class WhoisCommandFactoryTest {
.contains("Phone Number: +1.2345677890");
}
@Test
@TestOfyAndSql
void testCached_RegistrarLookupCommand() throws Exception {
WhoisResponse response =
cachedFactory.registrarLookup("OtherRegistrar").executeQuery(clock.nowUtc());
@ -213,7 +215,7 @@ class WhoisCommandFactoryTest {
.contains("Phone Number: +1.2223334444");
}
@Test
@TestOfyAndSql
void testNonCached_NameserverLookupByIpCommand() throws Exception {
// Note that this lookup currently doesn't cache the hosts, so there's no point in testing the
// "cached" case. This test is here so that it will fail if anyone adds caching.

View file

@ -41,9 +41,11 @@ import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.model.registry.Registry;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectExtension;
import google.registry.testing.TestOfyAndSql;
import google.registry.whois.WhoisMetrics.WhoisMetric;
import java.io.IOException;
import java.io.Reader;
@ -51,7 +53,6 @@ import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/**
@ -60,6 +61,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
* <p>This class should be limited to testing the HTTP interface, as the bulk of the WHOIS testing
* can be found in {@link WhoisActionTest}.
*/
@DualDatabaseTest
class WhoisHttpActionTest {
@RegisterExtension
@ -92,7 +94,7 @@ class WhoisHttpActionTest {
inject.setStaticField(Ofy.class, "clock", clock);
}
@Test
@TestOfyAndSql
void testRun_emptyQuery_returns400BadRequestWithPlainTextOutput() {
newWhoisHttpAction("").run();
assertThat(response.getStatus()).isEqualTo(400);
@ -100,7 +102,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_no_command.txt"));
}
@Test
@TestOfyAndSql
void testRun_badUrlEncoding_returns400BadRequestWithPlainTextOutput() {
newWhoisHttpAction("nic.%u307F%u3093%u306A").run();
assertThat(response.getStatus()).isEqualTo(400);
@ -108,7 +110,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_malformed_path.txt"));
}
@Test
@TestOfyAndSql
void testRun_domainNotFound_returns404StatusAndPlainTextResponse() {
newWhoisHttpAction("/domain/cat.lol").run();
assertThat(response.getStatus()).isEqualTo(404);
@ -118,7 +120,7 @@ class WhoisHttpActionTest {
// todo (b/27378695): reenable or delete this test
@Disabled
@Test
@TestOfyAndSql
void testRun_domainInTestTld_isConsideredNotFound() {
persistResource(Registry.get("lol").asBuilder().setTldType(Registry.TldType.TEST).build());
Registrar registrar = persistResource(makeRegistrar(
@ -138,7 +140,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_domain_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_domainQueryIdn_works() {
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", Registrar.State.ACTIVE));
@ -156,7 +158,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_idn_utf8.txt"));
}
@Test
@TestOfyAndSql
void testRun_wickedLineFeedForgeryInDatastore_crlfSubstitutedWithSpace() {
ContactResource trl = makeContactResource("5372808-TRL", "Eric Schmidt", "bog@cat.みんな");
trl =
@ -179,7 +181,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).contains("Galactic Empire");
}
@Test
@TestOfyAndSql
void testRun_domainOnly_works() {
persistResource(makeDomainBase(
"cat.みんな",
@ -194,14 +196,14 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).contains("Domain Name: cat.みんな\r\n");
}
@Test
@TestOfyAndSql
void testRun_hostnameOnly_works() {
persistResource(makeHostResource("ns1.cat.みんな", "1.2.3.4"));
newWhoisHttpAction("ns1.cat.みんな").run();
assertThat(response.getPayload()).contains("Server Name: ns1.cat.みんな\r\n");
}
@Test
@TestOfyAndSql
void testRun_domainQueryPunycode_works() {
Registrar registrar = persistResource(makeRegistrar(
"evilregistrar", "Yes Virginia", Registrar.State.ACTIVE));
@ -218,7 +220,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_idn_utf8.txt"));
}
@Test
@TestOfyAndSql
void testRun_nameserverQuery_works() {
persistResource(loadRegistrar("TheRegistrar").asBuilder().setUrl("http://my.fake.url").build());
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
@ -228,14 +230,14 @@ class WhoisHttpActionTest {
// todo (b/27378695): reenable or delete this test
@Disabled
@Test
@TestOfyAndSql
void testRun_nameserverQueryInTestTld_notFound() {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.lol").run();
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_nameserver.txt"));
}
@Test
@TestOfyAndSql
void testRun_lastUpdateTimestamp_isPresentInResponse() {
clock.setTo(DateTime.parse("2020-07-12T23:52:43Z"));
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
@ -244,7 +246,7 @@ class WhoisHttpActionTest {
.contains(">>> Last update of WHOIS database: 2020-07-12T23:52:43Z <<<");
}
@Test
@TestOfyAndSql
void testRun_nameserverQueryIdn_works() {
persistResource(makeHostResource("ns1.cat.みんな", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.みんな").run();
@ -252,7 +254,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
@TestOfyAndSql
void testRun_nameserverQueryPunycode_works() {
persistResource(makeHostResource("ns1.cat.みんな", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.xn--q9jyb4c").run();
@ -260,7 +262,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
@TestOfyAndSql
void testRun_trailingSlashInPath_getsIgnored() {
persistResource(makeHostResource("ns1.cat.みんな", "1.2.3.4"));
newWhoisHttpAction("/nameserver/ns1.cat.xn--q9jyb4c/").run();
@ -268,7 +270,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).contains("1.2.3.4");
}
@Test
@TestOfyAndSql
void testRun_uppercaseDomain_ignoresCasing() {
persistResource(makeDomainBase(
"cat.lol",
@ -282,7 +284,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).contains("Domain Name: cat.lol\r\n");
}
@Test
@TestOfyAndSql
void testRun_hairyPath_getsDecoded() {
persistResource(makeDomainBase(
"cat.lol",
@ -297,7 +299,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).contains("Domain Name: cat.lol\r\n");
}
@Test
@TestOfyAndSql
void testRun_registrarLookup_works() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", Registrar.State.ACTIVE));
@ -308,7 +310,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar.txt"));
}
@Test
@TestOfyAndSql
void testRun_registrarLookupInPendingState_returnsNotFound() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", Registrar.State.PENDING));
@ -318,7 +320,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_registrarLookupWithTestType_returnsNotFound() {
Registrar registrar = persistResource(
makeRegistrar("example", "Example Registrar, Inc.", Registrar.State.ACTIVE)
@ -329,7 +331,7 @@ class WhoisHttpActionTest {
assertThat(response.getPayload()).isEqualTo(loadFile("whois_action_registrar_not_found.txt"));
}
@Test
@TestOfyAndSql
void testRun_metricsLoggedForSuccessfulCommand() {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
WhoisHttpAction action = newWhoisHttpAction("/nameserver/ns1.cat.lol");
@ -344,7 +346,7 @@ class WhoisHttpActionTest {
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
@Test
@TestOfyAndSql
void testRun_metricsLoggedForUnsuccessfulCommand() {
WhoisHttpAction action = newWhoisHttpAction("nic.%u307F%u3093%u306A");
action.whoisMetrics = mock(WhoisMetrics.class);
@ -354,7 +356,7 @@ class WhoisHttpActionTest {
verify(action.whoisMetrics).recordWhoisMetric(eq(expected));
}
@Test
@TestOfyAndSql
void testRun_metricsLoggedForInternalServerError() throws Exception {
persistResource(makeHostResource("ns1.cat.lol", "1.2.3.4"));
WhoisHttpAction action = newWhoisHttpAction("ns1.cat.lol");

View file

@ -22,14 +22,16 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.flogger.LoggerConfig;
import com.google.common.testing.TestLogHandler;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.FakeClock;
import google.registry.testing.TestOfyAndSql;
import java.io.StringReader;
import java.util.logging.Level;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link WhoisReader}. */
@DualDatabaseTest
class WhoisReaderTest {
@RegisterExtension
@ -83,245 +85,245 @@ class WhoisReaderTest {
.isEqualTo("Example Registrar, Inc.");
}
@Test
@TestOfyAndSql
void testRegistrarLookupWithOneToken() throws Exception {
assertThat(this.<RegistrarLookupCommand>readCommand("Example").registrarName)
.isEqualTo("Example");
}
@Test
@TestOfyAndSql
void testDomainLookupWithoutCRLF() throws Exception {
assertLoadsExampleTld("example.tld");
}
@Test
@TestOfyAndSql
void testWhitespaceOnDomainLookupWithCommand() throws Exception {
assertLoadsExampleTld(" \t domain \t \t example.tld \r\n");
}
@Test
@TestOfyAndSql
void testDomainLookup() throws Exception {
assertLoadsExampleTld("example.tld\r\n");
}
@Test
@TestOfyAndSql
void testDomainLookupWithCommand() throws Exception {
assertLoadsExampleTld("domain example.tld\r\n");
}
@Test
@TestOfyAndSql
void testCaseInsensitiveDomainLookup() throws Exception {
assertLoadsExampleTld("EXAMPLE.TLD\r\n");
}
@Test
@TestOfyAndSql
void testCaseInsensitiveDomainLookupWithCommand() throws Exception {
assertLoadsExampleTld("DOMAIN EXAMPLE.TLD\r\n");
}
@Test
@TestOfyAndSql
void testIDNULabelDomainLookup() throws Exception {
assertLoadsIDN("مثال.إختبار\r\n");
}
@Test
@TestOfyAndSql
void testIDNULabelDomainLookupWithCommand() throws Exception {
assertLoadsIDN("domain مثال.إختبار\r\n");
}
@Test
@TestOfyAndSql
void testIDNALabelDomainLookupWithCommand() throws Exception {
assertLoadsIDN("domain xn--mgbh0fb.xn--kgbechtv\r\n");
}
@Test
@TestOfyAndSql
void testIDNALabelDomainLookup() throws Exception {
assertLoadsIDN("xn--mgbh0fb.xn--kgbechtv\r\n");
}
@Test
@TestOfyAndSql
void testTooManyArgsDomainLookup() {
assertThrows(WhoisException.class, () -> readCommand("domain example.tld foo.bar"));
}
@Test
@TestOfyAndSql
void testTooFewArgsDomainLookup() {
assertThrows(WhoisException.class, () -> readCommand("domain"));
}
@Test
@TestOfyAndSql
void testIllegalArgDomainLookup() {
assertThrows(WhoisException.class, () -> readCommand("domain 1.1"));
}
@Test
@TestOfyAndSql
void testNameserverLookupWithoutCRLF() throws Exception {
assertLoadsExampleNs("ns.example.tld");
}
@Test
@TestOfyAndSql
void testWhitespaceOnNameserverLookupWithCommand() throws Exception {
assertLoadsExampleNs(" \t nameserver \t \t ns.example.tld \r\n");
}
@Test
@TestOfyAndSql
void testNameserverLookup() throws Exception {
assertLoadsExampleNs("ns.example.tld\r\n");
}
@Test
@TestOfyAndSql
void testDeepNameserverLookup() throws Exception {
NameserverLookupByHostCommand command = readCommand("ns.foo.bar.baz.example.tld\r\n");
assertThat(command.domainOrHostName.toString()).isEqualTo("ns.foo.bar.baz.example.tld");
assertThat(command.domainOrHostName.toString()).isEqualTo("ns.foo.bar.baz.example.tld");
}
@Test
@TestOfyAndSql
void testNameserverLookupWithCommand() throws Exception {
assertLoadsExampleNs("nameserver ns.example.tld\r\n");
}
@Test
@TestOfyAndSql
void testCaseInsensitiveNameserverLookup() throws Exception {
assertLoadsExampleNs("NS.EXAMPLE.TLD\r\n");
}
@Test
@TestOfyAndSql
void testCaseInsensitiveNameserverLookupWithCommand() throws Exception {
assertLoadsExampleNs("NAMESERVER NS.EXAMPLE.TLD\r\n");
}
@Test
@TestOfyAndSql
void testIDNULabelNameserverLookup() throws Exception {
assertLoadsIDNNs("ns.مثال.إختبار\r\n");
}
@Test
@TestOfyAndSql
void testIDNULabelNameserverLookupWithCommand() throws Exception {
assertLoadsIDNNs("nameserver ns.مثال.إختبار\r\n");
}
@Test
@TestOfyAndSql
void testIDNALabelNameserverLookupWithCommand() throws Exception {
assertLoadsIDNNs("nameserver ns.xn--mgbh0fb.xn--kgbechtv\r\n");
}
@Test
@TestOfyAndSql
void testIDNALabelNameserverLookup() throws Exception {
assertLoadsIDNNs("ns.xn--mgbh0fb.xn--kgbechtv\r\n");
}
@Test
@TestOfyAndSql
void testTooManyArgsNameserverLookup() {
assertThrows(WhoisException.class, () -> readCommand("nameserver ns.example.tld foo.bar"));
}
@Test
@TestOfyAndSql
void testTooFewArgsNameserverLookup() {
assertThrows(WhoisException.class, () -> readCommand("nameserver"));
}
@Test
@TestOfyAndSql
void testIllegalArgNameserverLookup() {
assertThrows(WhoisException.class, () -> readCommand("nameserver 1.1"));
}
@Test
@TestOfyAndSql
void testRegistrarLookup() throws Exception {
assertLoadsRegistrar("registrar Example Registrar, Inc.");
}
@Test
@TestOfyAndSql
void testRegistrarLookupCaseInsensitive() throws Exception {
assertLoadsRegistrar("REGISTRAR Example Registrar, Inc.");
}
@Test
@TestOfyAndSql
void testRegistrarLookupWhitespace() throws Exception {
assertLoadsRegistrar(" \t registrar \t \tExample Registrar, Inc. ");
}
@Test
@TestOfyAndSql
void testRegistrarLookupByDefault() throws Exception {
assertLoadsRegistrar("Example Registrar, Inc.");
}
@Test
@TestOfyAndSql
void testRegistrarLookupOnTLD() throws Exception {
assertThat(this.<RegistrarLookupCommand>readCommand("com").registrarName).isEqualTo("com");
}
@Test
@TestOfyAndSql
void testRegistrarLookupNoArgs() {
assertThrows(WhoisException.class, () -> readCommand("registrar"));
}
@Test
@TestOfyAndSql
void testNameserverLookupByIp() throws Exception {
assertNsLookup("43.34.12.213", "43.34.12.213");
}
@Test
@TestOfyAndSql
void testNameserverLookupByIpv6() throws Exception {
assertNsLookup("1080:0:0:0:8:800:200c:417a", "1080:0:0:0:8:800:200c:417a");
}
@Test
@TestOfyAndSql
void testNameserverLookupByCompressedIpv6() throws Exception {
assertNsLookup("1080::8:800:200c:417a", "1080:0:0:0:8:800:200c:417a");
}
@Test
@TestOfyAndSql
void testNameserverLookupByNoncanonicalIpv6() throws Exception {
assertNsLookup("1080:0:0:0:8:800:200C:417A", "1080:0:0:0:8:800:200c:417a");
}
@Test
@TestOfyAndSql
void testNameserverLookupByBackwardsCompatibleIpv6() throws Exception {
assertNsLookup("::FFFF:129.144.52.38", "129.144.52.38");
}
@Test
@TestOfyAndSql
void testNameserverLookupByIpWithCommand() throws Exception {
assertNsLookup("nameserver 43.34.12.213", "43.34.12.213");
}
@Test
@TestOfyAndSql
void testNameserverLookupByIpv6WithCommand() throws Exception {
assertNsLookup("nameserver 1080:0:0:0:8:800:200C:417a", "1080:0:0:0:8:800:200c:417a");
}
@Test
@TestOfyAndSql
void testNameserverLookupByIpCaseInsenstive() throws Exception {
assertNsLookup("NAMESERVER 43.34.12.213", "43.34.12.213");
}
@Test
@TestOfyAndSql
void testNameserverLookupByIpWhitespace() throws Exception {
assertNsLookup(" \t\t NAMESERVER \t 43.34.12.213 \r\n", "43.34.12.213");
}
@Test
@TestOfyAndSql
void testNameserverLookupByIpTooManyArgs() {
assertThrows(WhoisException.class, () -> readCommand("nameserver 43.34.12.213 43.34.12.213"));
}
@Test
@TestOfyAndSql
void testMultilevelDomainLookup() throws Exception {
this.<DomainLookupCommand>readCommand("example.1.test");
}
@Test
@TestOfyAndSql
void testMultilevelNameserverLookup() throws Exception {
this.<NameserverLookupByHostCommand>readCommand("ns.example.1.test");
}
@Test
@TestOfyAndSql
void testDeepMultilevelNameserverLookup() throws Exception {
this.<NameserverLookupByHostCommand>readCommand("ns.corp.example.1.test");
}
@Test
@TestOfyAndSql
void testUnconfiguredTld() throws Exception {
this.<RegistrarLookupCommand>readCommand("example.test");
this.<RegistrarLookupCommand>readCommand("1.example.test");
@ -330,12 +332,12 @@ class WhoisReaderTest {
this.<RegistrarLookupCommand>readCommand("tld");
}
@Test
@TestOfyAndSql
void testNoArgs() {
assertThrows(WhoisException.class, () -> readCommand(""));
}
@Test
@TestOfyAndSql
void testLogsDomainLookupCommand() throws Exception {
readCommand("domain example.tld");
assertAboutLogs()
@ -344,7 +346,7 @@ class WhoisReaderTest {
Level.INFO, "Attempting domain lookup command using domain name example.tld");
}
@Test
@TestOfyAndSql
void testLogsNameserverLookupCommandWithIpAddress() throws Exception {
readCommand("nameserver 43.34.12.213");
assertAboutLogs()
@ -353,7 +355,7 @@ class WhoisReaderTest {
Level.INFO, "Attempting nameserver lookup command using 43.34.12.213 as an IP address");
}
@Test
@TestOfyAndSql
void testLogsNameserverLookupCommandWithHostname() throws Exception {
readCommand("nameserver ns.example.tld");
assertAboutLogs()
@ -362,7 +364,7 @@ class WhoisReaderTest {
Level.INFO, "Attempting nameserver lookup command using ns.example.tld as a hostname");
}
@Test
@TestOfyAndSql
void testLogsRegistrarLookupCommand() throws Exception {
readCommand("registrar Example Registrar, Inc.");
assertAboutLogs()
@ -372,7 +374,7 @@ class WhoisReaderTest {
"Attempting registrar lookup command using registrar Example Registrar, Inc.");
}
@Test
@TestOfyAndSql
void testLogsSingleArgumentNameserverLookupUsingIpAddress() throws Exception {
readCommand("43.34.12.213");
assertAboutLogs()
@ -381,7 +383,7 @@ class WhoisReaderTest {
Level.INFO, "Attempting nameserver lookup using 43.34.12.213 as an IP address");
}
@Test
@TestOfyAndSql
void testLogsSingleArgumentRegistrarLookup() throws Exception {
readCommand("test");
assertAboutLogs()
@ -390,7 +392,7 @@ class WhoisReaderTest {
Level.INFO, "Attempting registrar lookup using test as a registrar");
}
@Test
@TestOfyAndSql
void testLogsSingleArgumentDomainLookup() throws Exception {
readCommand("example.tld");
assertAboutLogs()
@ -399,7 +401,7 @@ class WhoisReaderTest {
Level.INFO, "Attempting domain lookup using example.tld as a domain name");
}
@Test
@TestOfyAndSql
void testLogsSingleArgumentNameserverLookupUsingHostname() throws Exception {
readCommand("ns.example.tld");
assertAboutLogs()
@ -408,7 +410,7 @@ class WhoisReaderTest {
Level.INFO, "Attempting nameserver lookup using ns.example.tld as a hostname");
}
@Test
@TestOfyAndSql
void testLogsMultipleArgumentsButNoParticularCommand() throws Exception {
readCommand("Example Registrar, Inc.");
assertAboutLogs()