1
0
mirror of https://github.com/google/nomulus synced 2026-05-19 14:21:48 +00:00

Compare commits

...

4 Commits

Author SHA1 Message Date
gbrodman
31bf4bd76d Add a third poll message column in TransferData for domain transfers (#974)
Because we don't store serverApproveEntities specifically as a set in
the SQL world, we need to make sure that the entities are all separated
and stored if they exist. For domain transfers, there exist three
separate poll messages (client losing, client gaining, autorenew) so we
need to store and retrieve that one.

Founnd this while converting domain transfer flows to SQL.
2021-02-25 17:22:53 -05:00
gbrodman
cc69d63802 Fix a few Java 9+isms and ignore IML files (#973)
This allows us to run tests in IDEA which is significantly quicker. We
shouldn't be using anything past Java 8 anyway since that's what GAE
runs with.
2021-02-25 14:59:00 -05:00
gbrodman
d73a15c697 Partially convert RDAP ofy calls to tm calls (#964)
* Partially convert RDAP ofy calls to tm calls

This converts the simple retrieval actions but does not touch the more
complicated search actions -- those use some ofy() query searching logic
and will likely end up being significantly more complicated than this
change. Here, though, we are just changing the calls that can be
converted easily to tm() lookups.

To change in future PRs:
- RdapDomainSearchAction
- RdapEntitySearchAction
- RdapNameserverSearchAction
- RdapSearchActionBase
2021-02-23 11:28:10 -05:00
gbrodman
f35eda6dc1 Update NPM plugin and hardcode versions of Node / NPM to use (#971)
* Update NPM plugin and hardcode versions of Node / NPM to use

The plugin we were using before was a bit old (last updated in March
2019) and this one is newer, updated, and updates the package-lock file
with the new dependency upgrades
2021-02-23 11:27:34 -05:00
23 changed files with 2715 additions and 4511 deletions

2
.gitignore vendored
View File

@@ -75,7 +75,7 @@ local.properties
autogenerated/
# IDEA
nomulus.iml
**/*.iml
nomulus.ipr
nomulus.iws

View File

@@ -40,7 +40,7 @@ plugins {
id 'com.github.johnrengelman.shadow' version '5.1.0'
// NodeJs plugin
id "com.moowork.node" version "1.2.0"
id "com.github.node-gradle.node" version "3.0.1"
id 'idea'
id 'com.diffplug.gradle.spotless' version '3.25.0'
@@ -49,6 +49,12 @@ plugins {
id 'com.dorongold.task-tree' version '1.5'
}
node {
download = true
version = "14.15.5"
npmVersion = "6.14.11"
}
wrapper {
distributionType = Wrapper.DistributionType.ALL
}

View File

@@ -23,7 +23,7 @@ import sys
import re
# We should never analyze any generated files
UNIVERSALLY_SKIPPED_PATTERNS = {"/build/", "cloudbuild-caches", "/out/", ".git/"}
UNIVERSALLY_SKIPPED_PATTERNS = {"/build/", "cloudbuild-caches", "/out/", ".git/", ".gradle/"}
# We can't rely on CI to have the Enum package installed so we do this instead.
FORBIDDEN = 1
REQUIRED = 2

View File

@@ -140,11 +140,13 @@ public class ReplayCommitLogsToSqlAction implements Runnable {
transaction.stream()
.sorted(ReplayCommitLogsToSqlAction::compareByWeight)
.forEach(
versionedEntity ->
versionedEntity
.getEntity()
.ifPresentOrElse(
this::handleEntityPut, () -> handleEntityDelete(versionedEntity)));
versionedEntity -> {
if (versionedEntity.getEntity().isPresent()) {
handleEntityPut(versionedEntity.getEntity().get());
} else {
handleEntityDelete(versionedEntity);
}
});
}
private void handleEntityPut(Entity entity) {

View File

@@ -996,6 +996,13 @@ public class Registrar extends ImmutableObject
return CACHE_BY_CLIENT_ID.get().values();
}
/** Loads all registrar keys using an in-memory cache. */
public static ImmutableSet<VKey<Registrar>> loadAllKeysCached() {
return CACHE_BY_CLIENT_ID.get().keySet().stream()
.map(Registrar::createVKey)
.collect(toImmutableSet());
}
/** Loads and returns a registrar entity by its client id directly from Datastore. */
public static Optional<Registrar> loadByClientId(String clientId) {
checkArgument(!Strings.isNullOrEmpty(clientId), "clientId must be specified");

View File

@@ -15,7 +15,6 @@
package google.registry.model.transfer;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.model.ImmutableObject.DoNotCompare;
import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.CollectionUtils.nullToEmpty;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
@@ -95,6 +94,9 @@ public abstract class TransferData<
// the transfer request flow, when the instance is loaded from Datastore, we cannot make this
// distinction because they are just VKeys. Also, the only way we use serverApproveEntities is to
// just delete all the entities referenced by the VKeys, so we don't need to make the distinction.
//
// In addition, there may be a third poll message for the autorenew poll message on domain
// transfer if applicable.
@Ignore
@Column(name = "transfer_poll_message_id_1")
Long pollMessageId1;
@@ -103,6 +105,10 @@ public abstract class TransferData<
@Column(name = "transfer_poll_message_id_2")
Long pollMessageId2;
@Ignore
@Column(name = "transfer_poll_message_id_3")
Long pollMessageId3;
public abstract boolean isEmpty();
@Nullable
@@ -177,6 +183,10 @@ public abstract class TransferData<
Key<PollMessage> ofyKey = Key.create(historyEntryKey, PollMessage.class, pollMessageId2);
entityKeysBuilder.add(PollMessage.createVKey(ofyKey));
}
if (pollMessageId3 != null) {
Key<PollMessage> ofyKey = Key.create(historyEntryKey, PollMessage.class, pollMessageId3);
entityKeysBuilder.add(PollMessage.createVKey(ofyKey));
}
serverApproveEntities = entityKeysBuilder.build();
}
@@ -189,6 +199,7 @@ public abstract class TransferData<
transferData.repoId = null;
transferData.pollMessageId1 = null;
transferData.pollMessageId2 = null;
transferData.pollMessageId3 = null;
return;
}
// Each element in serverApproveEntities should have the exact same Key<HistoryEntry> as its
@@ -204,6 +215,9 @@ public abstract class TransferData<
if (sortedPollMessageIds.size() >= 2) {
transferData.pollMessageId2 = sortedPollMessageIds.get(1);
}
if (sortedPollMessageIds.size() >= 3) {
transferData.pollMessageId3 = sortedPollMessageIds.get(2);
}
}
/**

View File

@@ -14,7 +14,8 @@
package google.registry.rdap;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.rdap.RdapUtils.getRegistrarByIanaIdentifier;
import static google.registry.rdap.RdapUtils.getRegistrarByName;
import static google.registry.request.Action.Method.GET;
@@ -23,9 +24,9 @@ import static google.registry.request.Action.Method.HEAD;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Longs;
import com.google.re2j.Pattern;
import com.googlecode.objectify.Key;
import google.registry.model.contact.ContactResource;
import google.registry.model.registrar.Registrar;
import google.registry.persistence.VKey;
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
import google.registry.rdap.RdapMetrics.EndpointType;
import google.registry.rdap.RdapObjectClasses.RdapEntity;
@@ -69,13 +70,14 @@ public class RdapEntityAction extends RdapActionBase {
// RDAP Technical Implementation Guide 2.3.1 - MUST support contact entity lookup using the
// handle
if (ROID_PATTERN.matcher(pathSearchString).matches()) {
Key<ContactResource> contactKey = Key.create(ContactResource.class, pathSearchString);
ContactResource contactResource = ofy().load().key(contactKey).now();
VKey<ContactResource> contactVKey = VKey.create(ContactResource.class, pathSearchString);
Optional<ContactResource> contactResource =
transactIfJpaTm(() -> tm().loadByKeyIfPresent(contactVKey));
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
// they are global, and might have different roles for different domains.
if (contactResource != null && isAuthorized(contactResource)) {
if (contactResource.isPresent() && isAuthorized(contactResource.get())) {
return rdapJsonFormatter.createRdapContactEntity(
contactResource, ImmutableSet.of(), OutputDataType.FULL);
contactResource.get(), ImmutableSet.of(), OutputDataType.FULL);
}
}

View File

@@ -20,8 +20,8 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
import static google.registry.model.EppResourceUtils.isLinked;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.rdap.RdapIcannStandardInformation.CONTACT_REDACTED_VALUE;
import static google.registry.util.CollectionUtils.union;
@@ -35,7 +35,6 @@ import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.InetAddresses;
import com.google.gson.JsonArray;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactAddress;
@@ -77,7 +76,6 @@ import java.net.URI;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
@@ -343,15 +341,11 @@ public class RdapJsonFormatter {
// Kick off the database loads of the nameservers that we will need, so it can load
// asynchronously while we load and process the contacts.
ImmutableSet<HostResource> loadedHosts =
ImmutableSet.copyOf(tm().loadByKeys(domainBase.getNameservers()).values());
transactIfJpaTm(
() -> ImmutableSet.copyOf(tm().loadByKeys(domainBase.getNameservers()).values()));
// Load the registrant and other contacts and add them to the data.
Map<Key<ContactResource>, ContactResource> loadedContacts =
ofy()
.load()
.keys(
domainBase.getReferencedContacts().stream()
.map(VKey::getOfyKey)
.collect(toImmutableSet()));
ImmutableMap<VKey<? extends ContactResource>, ContactResource> loadedContacts =
transactIfJpaTm(() -> tm().loadByKeysIfPresent(domainBase.getReferencedContacts()));
// RDAP Response Profile 2.7.3, A domain MUST have the REGISTRANT, ADMIN, TECH roles and MAY
// have others. We also add the BILLING.
//
@@ -359,16 +353,16 @@ public class RdapJsonFormatter {
// fields we don't want to show (as opposed to not having contacts at all) because of GDPR etc.
//
// the GDPR redaction is handled in createRdapContactEntity
ImmutableSetMultimap<Key<ContactResource>, Type> contactsToRoles =
ImmutableSetMultimap<VKey<ContactResource>, Type> contactsToRoles =
Streams.concat(
domainBase.getContacts().stream(),
Stream.of(DesignatedContact.create(Type.REGISTRANT, domainBase.getRegistrant())))
.sorted(DESIGNATED_CONTACT_ORDERING)
.collect(
toImmutableSetMultimap(
contact -> contact.getContactKey().getOfyKey(), DesignatedContact::getType));
DesignatedContact::getContactKey, DesignatedContact::getType));
for (Key<ContactResource> contactKey : contactsToRoles.keySet()) {
for (VKey<ContactResource> contactKey : contactsToRoles.keySet()) {
Set<RdapEntity.Role> roles =
contactsToRoles.get(contactKey).stream()
.map(RdapJsonFormatter::convertContactTypeToRdapRole)
@@ -430,10 +424,12 @@ public class RdapJsonFormatter {
statuses.add(StatusValue.LINKED);
}
if (hostResource.isSubordinate()
&& tm().loadByKey(hostResource.getSuperordinateDomain())
.cloneProjectedAtTime(getRequestTime())
.getStatusValues()
.contains(StatusValue.PENDING_TRANSFER)) {
&& transactIfJpaTm(
() ->
tm().loadByKey(hostResource.getSuperordinateDomain())
.cloneProjectedAtTime(getRequestTime())
.getStatusValues()
.contains(StatusValue.PENDING_TRANSFER))) {
statuses.add(StatusValue.PENDING_TRANSFER);
}
builder

View File

@@ -392,22 +392,6 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
return setOtherQueryAttributes(query, deletedItemHandling, resultSetMaxSize);
}
/** Handles searches by key using a simple string. */
static <T extends EppResource> Query<T> queryItemsByKey(
Class<T> clazz,
String queryString,
DeletedItemHandling deletedItemHandling,
int resultSetMaxSize) {
if (queryString.length() < RdapSearchPattern.MIN_INITIAL_STRING_LENGTH) {
throw new UnprocessableEntityException(
String.format(
"Initial search string must be at least %d characters",
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
}
Query<T> query = ofy().load().type(clazz).filterKey("=", Key.create(clazz, queryString));
return setOtherQueryAttributes(query, deletedItemHandling, resultSetMaxSize);
}
static <T extends EppResource> Query<T> setOtherQueryAttributes(
Query<T> query, DeletedItemHandling deletedItemHandling, int resultSetMaxSize) {
if (deletedItemHandling != DeletedItemHandling.INCLUDE) {

View File

@@ -16,7 +16,6 @@ package google.registry.rdap;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -34,7 +33,6 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.googlecode.objectify.Key;
import google.registry.keyring.api.KeyModule;
import google.registry.model.registrar.Registrar;
import google.registry.model.registry.Registries;
@@ -197,37 +195,37 @@ public final class UpdateRegistrarRdapBaseUrlsAction implements Runnable {
@Override
public void run() {
ImmutableSetMultimap<String, String> ianaToBaseUrls = getRdapBaseUrlsPerIanaId();
for (Key<Registrar> registrarKey : ofy().load().type(Registrar.class).keys()) {
tm()
.transact(
() -> {
Registrar registrar = ofy().load().key(registrarKey).now();
// Has the registrar been deleted since we loaded the key? (unlikly, especially
// given we don't delete registrars...)
if (registrar == null) {
return;
}
// Only update REAL registrars
if (registrar.getType() != Registrar.Type.REAL) {
return;
}
String ianaId = String.valueOf(registrar.getIanaIdentifier());
ImmutableSet<String> baseUrls = ianaToBaseUrls.get(ianaId);
// If this registrar already has these values, skip it
if (registrar.getRdapBaseUrls().equals(baseUrls)) {
logger.atInfo().log(
"No change in RdapBaseUrls for registrar %s (ianaId %s)",
registrar.getClientId(), ianaId);
return;
}
logger.atInfo().log(
"Updating RdapBaseUrls for registrar %s (ianaId %s) from %s to %s",
registrar.getClientId(), ianaId, registrar.getRdapBaseUrls(), baseUrls);
ofy()
.save()
.entity(registrar.asBuilder().setRdapBaseUrls(baseUrls).build());
});
}
Registrar.loadAllKeysCached()
.forEach(
(key) ->
tm().transact(
() -> {
Registrar registrar = tm().loadByKey(key);
// Has the registrar been deleted since we loaded the key? (unlikely,
// especially given we don't delete registrars...)
if (registrar == null) {
return;
}
// Only update REAL registrars
if (registrar.getType() != Registrar.Type.REAL) {
return;
}
String ianaId = String.valueOf(registrar.getIanaIdentifier());
ImmutableSet<String> baseUrls = ianaToBaseUrls.get(ianaId);
// If this registrar already has these values, skip it
if (registrar.getRdapBaseUrls().equals(baseUrls)) {
logger.atInfo().log(
"No change in RdapBaseUrls for registrar %s (ianaId %s)",
registrar.getClientId(), ianaId);
return;
}
logger.atInfo().log(
"Updating RdapBaseUrls for registrar %s (ianaId %s) from %s to %s",
registrar.getClientId(),
ianaId,
registrar.getRdapBaseUrls(),
baseUrls);
tm().put(registrar.asBuilder().setRdapBaseUrls(baseUrls).build());
}));
}
}

View File

@@ -151,7 +151,7 @@ public class BackfillRegistryLocksCommand extends ConfirmingCommand
return domains.stream()
.filter(d -> d.getDeletionTime().isAfter(now))
.filter(d -> d.getStatusValues().containsAll(REGISTRY_LOCK_STATUSES))
.filter(d -> RegistryLockDao.getMostRecentByRepoId(d.getRepoId()).isEmpty())
.filter(d -> !RegistryLockDao.getMostRecentByRepoId(d.getRepoId()).isPresent())
.collect(toImmutableList());
}
}

View File

@@ -36,7 +36,6 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collector;
import javax.annotation.Nullable;
@@ -244,7 +243,7 @@ public final class ImmutableObjectSubject extends Subject {
// We just need to check if there were any objects in "actual" that were not in "expected"
// (where "found" is a proxy for "expected").
} else if (actual.stream().anyMatch(Predicate.not(found::contains))) {
} else if (!found.containsAll(actual)) {
return ComparisonResult.createFailure();
}

View File

@@ -38,12 +38,14 @@ import google.registry.rdap.RdapMetrics.SearchType;
import google.registry.rdap.RdapMetrics.WildcardType;
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
import google.registry.request.Action;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.TestOfyAndSql;
import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link RdapEntityAction}. */
@DualDatabaseTest
class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
RdapEntityActionTest() {
@@ -187,35 +189,35 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
assertThat(response.getStatus()).isEqualTo(404);
}
@Test
@TestOfyAndSql
void testUnknownEntity_RoidPattern_notFound() {
runNotFoundTest("_MISSING-ENTITY_");
}
@Test
@TestOfyAndSql
void testUnknownEntity_IanaPattern_notFound() {
runNotFoundTest("123");
}
@Test
@TestOfyAndSql
void testUnknownEntity_notRoidNotIana_notFound() {
// Since we allow search by registrar name, every string is a possible name
runNotFoundTest("some,random,string");
}
@Test
@TestOfyAndSql
void testValidRegistrantContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(registrant.getRepoId(), "rdap_associated_contact.json");
}
@Test
@TestOfyAndSql
void testValidRegistrantContact_found_asAdministrator() {
loginAsAdmin();
runSuccessfulHandleTest(registrant.getRepoId(), "rdap_associated_contact.json");
}
@Test
@TestOfyAndSql
void testValidRegistrantContact_found_notLoggedIn() {
runSuccessfulHandleTest(
registrant.getRepoId(),
@@ -225,7 +227,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
"rdap_associated_contact_no_personal_data.json");
}
@Test
@TestOfyAndSql
void testValidRegistrantContact_found_loggedInAsOtherRegistrar() {
login("otherregistrar");
runSuccessfulHandleTest(
@@ -236,49 +238,49 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
"rdap_associated_contact_no_personal_data.json");
}
@Test
@TestOfyAndSql
void testValidAdminContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(adminContact.getRepoId(), "rdap_associated_contact.json");
}
@Test
@TestOfyAndSql
void testValidTechContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(techContact.getRepoId(), "rdap_associated_contact.json");
}
@Test
@TestOfyAndSql
void testValidDisconnectedContact_works() {
login("evilregistrar");
runSuccessfulHandleTest(disconnectedContact.getRepoId(), "rdap_contact.json");
}
@Test
@TestOfyAndSql
void testDeletedContact_notFound() {
runNotFoundTest(deletedContact.getRepoId());
}
@Test
@TestOfyAndSql
void testDeletedContact_notFound_includeDeletedSetFalse() {
action.includeDeletedParam = Optional.of(false);
runNotFoundTest(deletedContact.getRepoId());
}
@Test
@TestOfyAndSql
void testDeletedContact_notFound_notLoggedIn() {
action.includeDeletedParam = Optional.of(true);
runNotFoundTest(deletedContact.getRepoId());
}
@Test
@TestOfyAndSql
void testDeletedContact_notFound_loggedInAsDifferentRegistrar() {
login("idnregistrar");
action.includeDeletedParam = Optional.of(true);
runNotFoundTest(deletedContact.getRepoId());
}
@Test
@TestOfyAndSql
void testDeletedContact_found_loggedInAsCorrectRegistrar() {
login("evilregistrar");
action.includeDeletedParam = Optional.of(true);
@@ -290,7 +292,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
"rdap_contact_deleted.json");
}
@Test
@TestOfyAndSql
void testDeletedContact_found_loggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
@@ -302,12 +304,12 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
"rdap_contact_deleted.json");
}
@Test
@TestOfyAndSql
void testRegistrar_found() {
runSuccessfulHandleTest("101", "Yes Virginia <script>", "rdap_registrar.json");
}
@Test
@TestOfyAndSql
void testRegistrarByName_found() {
assertThat(generateActualJson("IDN%20Registrar"))
.isEqualTo(
@@ -316,28 +318,28 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
@TestOfyAndSql
void testRegistrar102_works() {
runSuccessfulHandleTest("102", "IDN Registrar", "rdap_registrar.json");
}
@Test
@TestOfyAndSql
void testRegistrar103_works() {
runSuccessfulHandleTest("103", "Multilevel Registrar", "rdap_registrar.json");
}
@Test
@TestOfyAndSql
void testRegistrar104_notFound() {
runNotFoundTest("104");
}
@Test
@TestOfyAndSql
void testRegistrar104_notFound_deletedFlagWhenNotLoggedIn() {
action.includeDeletedParam = Optional.of(true);
runNotFoundTest("104");
}
@Test
@TestOfyAndSql
void testRegistrar104_found_deletedFlagWhenLoggedIn() {
login("deletedregistrar");
action.includeDeletedParam = Optional.of(true);
@@ -345,14 +347,14 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
"104", "Yes Virginia <script>", "inactive", null, "rdap_registrar.json");
}
@Test
@TestOfyAndSql
void testRegistrar104_notFound_deletedFlagWhenLoggedInAsOther() {
login("1tldregistrar");
action.includeDeletedParam = Optional.of(true);
runNotFoundTest("104");
}
@Test
@TestOfyAndSql
void testRegistrar104_found_deletedFlagWhenLoggedInAsAdmin() {
loginAsAdmin();
action.includeDeletedParam = Optional.of(true);
@@ -360,12 +362,12 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
"104", "Yes Virginia <script>", "inactive", null, "rdap_registrar.json");
}
@Test
@TestOfyAndSql
void testRegistrar105_doesNotExist() {
runNotFoundTest("105");
}
@Test
@TestOfyAndSql
void testQueryParameter_ignored() {
login("evilregistrar");
assertThat(generateActualJson(techContact.getRepoId() + "?key=value")).isEqualTo(
@@ -374,7 +376,7 @@ class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityAction> {
assertThat(response.getStatus()).isEqualTo(200);
}
@Test
@TestOfyAndSql
void testMetrics() {
generateActualJson(registrant.getRepoId());
verify(rdapMetrics)

View File

@@ -47,14 +47,16 @@ import google.registry.rdap.RdapObjectClasses.RdapEntity;
import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
import google.registry.rdap.RdapObjectClasses.TopLevelReplyObject;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectExtension;
import google.registry.testing.TestOfyAndSql;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link RdapJsonFormatter}. */
@DualDatabaseTest
class RdapJsonFormatterTest {
@RegisterExtension
@@ -300,41 +302,41 @@ class RdapJsonFormatterTest {
return new Gson().fromJson(loadFile(this.getClass(), expectedFileName), JsonObject.class);
}
@Test
@TestOfyAndSql
void testRegistrar() {
assertThat(rdapJsonFormatter.createRdapRegistrarEntity(registrar, OutputDataType.FULL).toJson())
.isEqualTo(loadJson("rdapjson_registrar.json"));
}
@Test
@TestOfyAndSql
void testRegistrar_summary() {
assertThat(
rdapJsonFormatter.createRdapRegistrarEntity(registrar, OutputDataType.SUMMARY).toJson())
.isEqualTo(loadJson("rdapjson_registrar_summary.json"));
}
@Test
@TestOfyAndSql
void testHost_ipv4() {
assertThat(
rdapJsonFormatter.createRdapNameserver(hostResourceIpv4, OutputDataType.FULL).toJson())
.isEqualTo(loadJson("rdapjson_host_ipv4.json"));
}
@Test
@TestOfyAndSql
void testHost_ipv6() {
assertThat(
rdapJsonFormatter.createRdapNameserver(hostResourceIpv6, OutputDataType.FULL).toJson())
.isEqualTo(loadJson("rdapjson_host_ipv6.json"));
}
@Test
@TestOfyAndSql
void testHost_both() {
assertThat(
rdapJsonFormatter.createRdapNameserver(hostResourceBoth, OutputDataType.FULL).toJson())
.isEqualTo(loadJson("rdapjson_host_both.json"));
}
@Test
@TestOfyAndSql
void testHost_both_summary() {
assertThat(
rdapJsonFormatter
@@ -343,7 +345,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_host_both_summary.json"));
}
@Test
@TestOfyAndSql
void testHost_noAddresses() {
assertThat(
rdapJsonFormatter
@@ -352,7 +354,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_host_no_addresses.json"));
}
@Test
@TestOfyAndSql
void testHost_notLinked() {
assertThat(
rdapJsonFormatter
@@ -361,7 +363,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_host_not_linked.json"));
}
@Test
@TestOfyAndSql
void testHost_superordinateHasPendingTransfer() {
assertThat(
rdapJsonFormatter
@@ -370,7 +372,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_host_pending_transfer.json"));
}
@Test
@TestOfyAndSql
void testRegistrant() {
assertThat(
rdapJsonFormatter
@@ -382,7 +384,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_registrant.json"));
}
@Test
@TestOfyAndSql
void testRegistrant_summary() {
assertThat(
rdapJsonFormatter
@@ -394,7 +396,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_registrant_summary.json"));
}
@Test
@TestOfyAndSql
void testRegistrant_loggedOut() {
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
assertThat(
@@ -407,7 +409,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_registrant_logged_out.json"));
}
@Test
@TestOfyAndSql
void testRegistrant_baseHasNoTrailingSlash() {
// First, make sure we have a trailing slash at the end by default!
// This test tries to change the default state, if the default doesn't have a /, then this test
@@ -426,7 +428,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_registrant.json"));
}
@Test
@TestOfyAndSql
void testAdmin() {
assertThat(
rdapJsonFormatter
@@ -438,7 +440,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_admincontact.json"));
}
@Test
@TestOfyAndSql
void testTech() {
assertThat(
rdapJsonFormatter
@@ -448,7 +450,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_techcontact.json"));
}
@Test
@TestOfyAndSql
void testRolelessContact() {
assertThat(
rdapJsonFormatter
@@ -458,7 +460,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_rolelesscontact.json"));
}
@Test
@TestOfyAndSql
void testUnlinkedContact() {
assertThat(
rdapJsonFormatter
@@ -468,26 +470,26 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_unlinkedcontact.json"));
}
@Test
@TestOfyAndSql
void testDomain_full() {
assertThat(rdapJsonFormatter.createRdapDomain(domainBaseFull, OutputDataType.FULL).toJson())
.isEqualTo(loadJson("rdapjson_domain_full.json"));
}
@Test
@TestOfyAndSql
void testDomain_summary() {
assertThat(rdapJsonFormatter.createRdapDomain(domainBaseFull, OutputDataType.SUMMARY).toJson())
.isEqualTo(loadJson("rdapjson_domain_summary.json"));
}
@Test
@TestOfyAndSql
void testDomain_logged_out() {
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
assertThat(rdapJsonFormatter.createRdapDomain(domainBaseFull, OutputDataType.FULL).toJson())
.isEqualTo(loadJson("rdapjson_domain_logged_out.json"));
}
@Test
@TestOfyAndSql
void testDomain_noNameserversNoTransfersMultipleRoleContact() {
assertThat(
rdapJsonFormatter
@@ -496,7 +498,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_domain_no_nameservers.json"));
}
@Test
@TestOfyAndSql
void testError() {
assertThat(
RdapObjectClasses.ErrorResponse.create(
@@ -505,7 +507,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_error.json"));
}
@Test
@TestOfyAndSql
void testTopLevel() {
assertThat(
TopLevelReplyObject.create(
@@ -517,7 +519,7 @@ class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_toplevel.json"));
}
@Test
@TestOfyAndSql
void testTopLevel_domain() {
assertThat(
TopLevelReplyObject.create(

View File

@@ -35,13 +35,15 @@ import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldType;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.TestOfyAndSql;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link UpdateRegistrarRdapBaseUrlsAction}. */
@DualDatabaseTest
public final class UpdateRegistrarRdapBaseUrlsActionTest {
/**
@@ -160,7 +162,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
.build());
}
@Test
@TestOfyAndSql
void testUnknownIana_cleared() {
// The IANA ID isn't in the JSON_LIST_REPLY
persistRegistrar("someRegistrar", 4123L, Registrar.Type.REAL, "http://rdap.example/blah");
@@ -172,7 +174,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
assertThat(loadRegistrar("someRegistrar").getRdapBaseUrls()).isEmpty();
}
@Test
@TestOfyAndSql
void testKnownIana_changed() {
// The IANA ID is in the JSON_LIST_REPLY
persistRegistrar("someRegistrar", 1448L, Registrar.Type.REAL, "http://rdap.example/blah");
@@ -185,7 +187,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
.containsExactly("https://rdap.blacknight.com");
}
@Test
@TestOfyAndSql
void testKnownIana_notReal_noChange() {
// The IANA ID is in the JSON_LIST_REPLY
persistRegistrar("someRegistrar", 9999L, Registrar.Type.INTERNAL, "http://rdap.example/blah");
@@ -198,7 +200,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
.containsExactly("http://rdap.example/blah");
}
@Test
@TestOfyAndSql
void testKnownIana_notReal_nullIANA_noChange() {
persistRegistrar("someRegistrar", null, Registrar.Type.TEST, "http://rdap.example/blah");
@@ -210,7 +212,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
.containsExactly("http://rdap.example/blah");
}
@Test
@TestOfyAndSql
void testKnownIana_multipleValues() {
// The IANA ID is in the JSON_LIST_REPLY
persistRegistrar("registrar4000", 4000L, Registrar.Type.REAL, "http://rdap.example/blah");
@@ -227,7 +229,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
.containsExactly("https://rdap.example.com");
}
@Test
@TestOfyAndSql
void testNoTlds() {
deleteTld("tld");
assertThat(assertThrows(IllegalArgumentException.class, action::run))
@@ -235,7 +237,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
.isEqualTo("There must exist at least one REAL TLD.");
}
@Test
@TestOfyAndSql
void testOnlyTestTlds() {
persistResource(Registry.get("tld").asBuilder().setTldType(TldType.TEST).build());
assertThat(assertThrows(IllegalArgumentException.class, action::run))
@@ -243,7 +245,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
.isEqualTo("There must exist at least one REAL TLD.");
}
@Test
@TestOfyAndSql
void testSecondTldSucceeds() {
createTld("secondtld");
httpTransport = new TestHttpTransport();
@@ -261,7 +263,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
action.run();
}
@Test
@TestOfyAndSql
void testBothFail() {
createTld("secondtld");
httpTransport = new TestHttpTransport();
@@ -281,7 +283,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
.isEqualTo("Error contacting MosAPI server. Tried TLDs [secondtld, tld]");
}
@Test
@TestOfyAndSql
void testFailureCause_ignoresLoginFailure() {
// Login failures aren't particularly interesting so we should log them, but the final
// throwable should be some other failure if one existed

View File

@@ -261,11 +261,11 @@ td.section {
</tr>
<tr>
<td class="property_name">generated on</td>
<td class="property_value">2021-01-21 00:11:27.19594</td>
<td class="property_value">2021-02-25 19:33:39.25711</td>
</tr>
<tr>
<td class="property_name">last flyway file</td>
<td id="lastFlywayFile" class="property_value">V85__add_required_columns_in_transfer_data.sql</td>
<td id="lastFlywayFile" class="property_value">V86__third_poll_message.sql</td>
</tr>
</tbody>
</table>
@@ -284,7 +284,7 @@ td.section {
generated on
</text>
<text text-anchor="start" x="4035.94" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">
2021-01-21 00:11:27.19594
2021-02-25 19:33:39.25711
</text>
<polygon fill="none" stroke="#888888" points="3948.44,-4 3948.44,-44 4205.44,-44 4205.44,-4 3948.44,-4" /> <!-- allocationtoken_a08ccbef -->
<g id="node1" class="node">

File diff suppressed because it is too large Load Diff

View File

@@ -83,3 +83,4 @@ V82__add_columns_to_restore_symmetric_billing_vkey.sql
V83__add_indexes_on_domainhost.sql
V84__add_vkey_columns_in_billing_cancellation.sql
V85__add_required_columns_in_transfer_data.sql
V86__third_poll_message.sql

View File

@@ -0,0 +1,20 @@
-- Copyright 2021 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.
ALTER TABLE "Contact" ADD COLUMN IF NOT EXISTS "transfer_poll_message_id_3" bigint;
ALTER TABLE "ContactHistory" ADD COLUMN IF NOT EXISTS "transfer_poll_message_id_3" bigint;
ALTER TABLE "Domain" ADD COLUMN IF NOT EXISTS "transfer_poll_message_id_3" bigint;
ALTER TABLE "DomainHistory" ADD COLUMN IF NOT EXISTS "transfer_poll_message_id_3" bigint;
ALTER TABLE "Host" ADD COLUMN IF NOT EXISTS "transfer_poll_message_id_3" bigint;
ALTER TABLE "HostHistory" ADD COLUMN IF NOT EXISTS "transfer_poll_message_id_3" bigint;

View File

@@ -143,6 +143,7 @@
transfer_history_entry_id int8,
transfer_poll_message_id_1 int8,
transfer_poll_message_id_2 int8,
transfer_poll_message_id_3 int8,
transfer_repo_id text,
transfer_client_txn_id text,
transfer_server_txn_id text,
@@ -206,6 +207,7 @@
transfer_history_entry_id int8,
transfer_poll_message_id_1 int8,
transfer_poll_message_id_2 int8,
transfer_poll_message_id_3 int8,
transfer_repo_id text,
transfer_client_txn_id text,
transfer_server_txn_id text,
@@ -291,6 +293,7 @@
transfer_history_entry_id int8,
transfer_poll_message_id_1 int8,
transfer_poll_message_id_2 int8,
transfer_poll_message_id_3 int8,
transfer_repo_id text,
transfer_client_txn_id text,
transfer_server_txn_id text,
@@ -362,6 +365,7 @@
transfer_history_entry_id int8,
transfer_poll_message_id_1 int8,
transfer_poll_message_id_2 int8,
transfer_poll_message_id_3 int8,
transfer_repo_id text,
transfer_client_txn_id text,
transfer_server_txn_id text,

View File

@@ -221,7 +221,8 @@ CREATE TABLE public."Contact" (
transfer_status text,
update_timestamp timestamp with time zone,
transfer_history_entry_id bigint,
transfer_repo_id text
transfer_repo_id text,
transfer_poll_message_id_3 bigint
);
@@ -296,7 +297,8 @@ CREATE TABLE public."ContactHistory" (
contact_repo_id text NOT NULL,
update_timestamp timestamp with time zone,
transfer_history_entry_id bigint,
transfer_repo_id text
transfer_repo_id text,
transfer_poll_message_id_3 bigint
);
@@ -383,7 +385,8 @@ CREATE TABLE public."Domain" (
transfer_autorenew_poll_message_history_id bigint,
transfer_billing_event_history_id bigint,
transfer_history_entry_id bigint,
transfer_repo_id text
transfer_repo_id text,
transfer_poll_message_id_3 bigint
);
@@ -473,7 +476,8 @@ CREATE TABLE public."DomainHistory" (
transfer_autorenew_poll_message_history_id bigint,
transfer_billing_event_history_id bigint,
transfer_history_entry_id bigint,
transfer_repo_id text
transfer_repo_id text,
transfer_poll_message_id_3 bigint
);
@@ -590,7 +594,8 @@ CREATE TABLE public."Host" (
last_transfer_time timestamp with time zone,
superordinate_domain text,
inet_addresses text[],
update_timestamp timestamp with time zone
update_timestamp timestamp with time zone,
transfer_poll_message_id_3 bigint
);
@@ -622,7 +627,8 @@ CREATE TABLE public."HostHistory" (
last_epp_update_time timestamp with time zone,
statuses text[],
host_repo_id text NOT NULL,
update_timestamp timestamp with time zone
update_timestamp timestamp with time zone,
transfer_poll_message_id_3 bigint
);

View File

@@ -11,6 +11,8 @@ com.diffplug.spotless:spotless-plugin-gradle:3.25.0
com.dorongold.task-tree:com.dorongold.task-tree.gradle.plugin:1.5
com.github.jengelman.gradle.plugins:shadow:5.1.0
com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:5.1.0
com.github.node-gradle.node:com.github.node-gradle.node.gradle.plugin:3.0.1
com.github.node-gradle:gradle-node-plugin:3.0.1
com.google.cloud.tools:appengine-gradle-plugin:2.0.1
com.google.cloud.tools:appengine-plugins-core:0.7.5
com.google.code.findbugs:jsr305:3.0.2
@@ -24,8 +26,6 @@ com.googlecode.concurrent-trees:concurrent-trees:2.6.1
com.googlecode.javaewah:JavaEWAH:1.1.6
com.jcraft:jsch:0.1.55
com.jcraft:jzlib:1.1.1
com.moowork.gradle:gradle-node-plugin:1.2.0
com.moowork.node:com.moowork.node.gradle.plugin:1.2.0
com.netflix.nebula:gradle-lint-plugin:16.0.2
com.netflix.nebula:nebula-gradle-interop:1.0.11
commons-io:commons-io:2.6

2051
package-lock.json generated

File diff suppressed because it is too large Load Diff