1
0
mirror of https://github.com/google/nomulus synced 2025-12-23 06:15:42 +00:00

Make RDE generation resilient to missing contact rows (#2883)

This will prevent RDE from failing once we delete all contacts, just as a
fail-safe.

BUG= http://b/439636188
This commit is contained in:
Ben McIlwain
2025-11-13 15:09:43 -05:00
committed by GitHub
parent 759aaddb5f
commit 5f0526c07a
2 changed files with 31 additions and 17 deletions

View File

@@ -168,20 +168,18 @@ final class DomainToXjcConverter {
// as the holder of the domain name object. // as the holder of the domain name object.
Optional<VKey<Contact>> registrant = model.getRegistrant(); Optional<VKey<Contact>> registrant = model.getRegistrant();
if (registrant.isPresent()) { if (registrant.isPresent()) {
Contact registrantContact = tm().transact(() -> tm().loadByKey(registrant.get())); Optional<Contact> registrantContact =
checkState( tm().transact(() -> tm().loadByKeyIfPresent(registrant.get()));
registrantContact != null, registrantContact.ifPresent(c -> bean.setRegistrant(c.getContactId()));
"Registrant contact %s on domain %s does not exist",
registrant,
domainName);
bean.setRegistrant(registrantContact.getContactId());
} }
// o Zero or more OPTIONAL <contact> elements that contain identifiers // o Zero or more OPTIONAL <contact> elements that contain identifiers
// for the human or organizational social information objects // for the human or organizational social information objects
// associated with the domain name object. // associated with the domain name object.
for (DesignatedContact contact : model.getContacts()) { for (DesignatedContact contact : model.getContacts()) {
bean.getContacts().add(convertDesignatedContact(contact, domainName)); Optional<XjcDomainContactType> contactType =
convertDesignatedContact(contact, domainName);
contactType.ifPresent(c -> bean.getContacts().add(c));
} }
// o An OPTIONAL <secDNS> element that contains the public key // o An OPTIONAL <secDNS> element that contains the public key
@@ -292,7 +290,7 @@ final class DomainToXjcConverter {
} }
/** Converts {@link DesignatedContact} to {@link XjcDomainContactType}. */ /** Converts {@link DesignatedContact} to {@link XjcDomainContactType}. */
private static XjcDomainContactType convertDesignatedContact( private static Optional<XjcDomainContactType> convertDesignatedContact(
DesignatedContact model, String domainName) { DesignatedContact model, String domainName) {
XjcDomainContactType bean = new XjcDomainContactType(); XjcDomainContactType bean = new XjcDomainContactType();
checkState( checkState(
@@ -300,15 +298,13 @@ final class DomainToXjcConverter {
"Contact key for type %s is null on domain %s", "Contact key for type %s is null on domain %s",
model.getType(), model.getType(),
domainName); domainName);
Contact contact = tm().transact(() -> tm().loadByKey(model.getContactKey())); Optional<Contact> contact = tm().transact(() -> tm().loadByKeyIfPresent(model.getContactKey()));
checkState( if (contact.isEmpty()) {
contact != null, return Optional.empty();
"Contact %s on domain %s does not exist", }
model.getContactKey(),
domainName);
bean.setType(XjcDomainContactAttrType.fromValue(Ascii.toLowerCase(model.getType().toString()))); bean.setType(XjcDomainContactAttrType.fromValue(Ascii.toLowerCase(model.getType().toString())));
bean.setValue(contact.getContactId()); bean.setValue(contact.get().getContactId());
return bean; return Optional.of(bean);
} }
private DomainToXjcConverter() {} private DomainToXjcConverter() {}

View File

@@ -14,9 +14,11 @@
package google.registry.rde; package google.registry.rde;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage; import static com.google.common.truth.Truth.assertWithMessage;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.createTld; import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistEppResource; import static google.registry.testing.DatabaseHelper.persistEppResource;
import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.testing.DatabaseHelper.persistResource;
@@ -69,6 +71,7 @@ import google.registry.xjc.rdedomain.XjcRdeDomain;
import google.registry.xjc.rdedomain.XjcRdeDomainElement; import google.registry.xjc.rdedomain.XjcRdeDomainElement;
import google.registry.xjc.rgp.XjcRgpStatusType; import google.registry.xjc.rgp.XjcRgpStatusType;
import google.registry.xjc.secdns.XjcSecdnsDsDataType; import google.registry.xjc.secdns.XjcSecdnsDsDataType;
import google.registry.xml.XmlException;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.util.Optional; import java.util.Optional;
import org.joda.money.Money; import org.joda.money.Money;
@@ -198,6 +201,21 @@ public class DomainToXjcConverterTest {
wrapDeposit(bean).marshal(new ByteArrayOutputStream(), UTF_8); wrapDeposit(bean).marshal(new ByteArrayOutputStream(), UTF_8);
} }
@Test
void testConvertAbsentContacts() throws XmlException {
Domain domain = makeDomain(clock);
tm().transact(
() ->
tm().delete(
domain.getAllContacts().stream()
.map(DesignatedContact::getContactKey)
.collect(toImmutableSet())));
XjcRdeDomain bean = DomainToXjcConverter.convertDomain(domain, RdeMode.FULL);
assertThat(bean.getRegistrant()).isNull();
assertThat(bean.getContacts()).isEmpty();
wrapDeposit(bean).marshal(new ByteArrayOutputStream(), UTF_8);
}
XjcRdeDeposit wrapDeposit(XjcRdeDomain domain) { XjcRdeDeposit wrapDeposit(XjcRdeDomain domain) {
XjcRdeDeposit deposit = new XjcRdeDeposit(); XjcRdeDeposit deposit = new XjcRdeDeposit();
deposit.setId("984302"); deposit.setId("984302");