Handle pending transfers on domain imports from RDE deposits

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=148496597
This commit is contained in:
Wolfgang Meyers 2017-02-24 13:27:07 -08:00 committed by Ben McIlwain
parent 3ca9bb6aeb
commit 9f90597691
14 changed files with 752 additions and 125 deletions

View file

@ -10,9 +10,11 @@ java_library(
deps = [
"//java/google/registry/config",
"//java/google/registry/dns",
"//java/google/registry/flows",
"//java/google/registry/gcs",
"//java/google/registry/mapreduce",
"//java/google/registry/model",
"//java/google/registry/pricing",
"//java/google/registry/request",
"//java/google/registry/util",
"//java/google/registry/xjc",
@ -28,5 +30,6 @@ java_library(
"@com_google_guava",
"@javax_servlet_api",
"@joda_time",
"@org_joda_money",
],
)

View file

@ -140,7 +140,7 @@ public class RdeContactImportAction implements Runnable {
public void vrun() {
ContactResource contact =
XjcToContactResourceConverter.convertContact(xjcContact);
getImportUtils().importContact(contact);
getImportUtils().importEppResource(contact);
}
});
// Record number of contacts imported

View file

@ -14,10 +14,18 @@
package google.registry.rde.imports;
import static google.registry.flows.domain.DomainTransferUtils.createLosingTransferPollMessage;
import static google.registry.flows.domain.DomainTransferUtils.createPendingTransferData;
import static google.registry.flows.domain.DomainTransferUtils.createTransferServerApproveEntities;
import static google.registry.mapreduce.MapreduceRunner.PARAM_MAP_SHARDS;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import static google.registry.rde.imports.RdeImportUtils.createAutoRenewBillingEventForDomainImport;
import static google.registry.rde.imports.RdeImportUtils.createAutoRenewPollMessageForDomainImport;
import static google.registry.rde.imports.RdeImportUtils.createHistoryEntryForDomainImport;
import static google.registry.rde.imports.RdeImportsModule.PATH;
import static google.registry.util.PipelineUtils.createJobPath;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
@ -25,13 +33,20 @@ import com.google.appengine.tools.cloudstorage.RetryParams;
import com.google.appengine.tools.mapreduce.Mapper;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.VoidWork;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.dns.DnsQueue;
import google.registry.gcs.GcsUtils;
import google.registry.mapreduce.MapreduceRunner;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.DomainResource;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferData.TransferServerApproveEntity;
import google.registry.model.transfer.TransferStatus;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.Response;
@ -41,6 +56,7 @@ import google.registry.xjc.JaxbFragment;
import google.registry.xjc.rdedomain.XjcRdeDomain;
import google.registry.xjc.rdedomain.XjcRdeDomainElement;
import javax.inject.Inject;
import org.joda.money.Money;
/**
* A mapreduce that imports domains from an escrow file.
@ -145,17 +161,70 @@ public class RdeDomainImportAction implements Runnable {
public void map(JaxbFragment<XjcRdeDomainElement> fragment) {
final XjcRdeDomain xjcDomain = fragment.getInstance().getValue();
try {
logger.infofmt("Converting xml for domain %s", xjcDomain.getName());
// Record number of attempted map operations
getContext().incrementCounter("domain imports attempted");
logger.infofmt("Saving domain %s", xjcDomain.getName());
ofy().transact(new VoidWork() {
@Override
public void vrun() {
DomainResource domain =
XjcToDomainResourceConverter.convertDomain(xjcDomain);
getImportUtils().importDomain(domain);
HistoryEntry historyEntry = createHistoryEntryForDomainImport(xjcDomain);
BillingEvent.Recurring autorenewBillingEvent =
createAutoRenewBillingEventForDomainImport(xjcDomain, historyEntry);
PollMessage.Autorenew autorenewPollMessage =
createAutoRenewPollMessageForDomainImport(xjcDomain, historyEntry);
DomainResource domain = XjcToDomainResourceConverter.convertDomain(
xjcDomain, autorenewBillingEvent, autorenewPollMessage);
getDnsQueue().addDomainRefreshTask(domain.getFullyQualifiedDomainName());
// Keep a list of "extra objects" that need to be saved along with the domain
// and add to it if necessary.
ImmutableSet<Object> extraEntitiesToSave =
getImportUtils().createIndexesForEppResource(domain);
// Create speculative server approval entities for pending transfers
if (domain.getTransferData().getTransferStatus() == TransferStatus.PENDING) {
TransferData transferData = domain.getTransferData();
checkArgumentNotNull(transferData,
"Domain %s is in pending transfer but has no transfer data",
domain.getFullyQualifiedDomainName());
Money transferCost = getDomainRenewCost(
domain.getFullyQualifiedDomainName(),
transferData.getPendingTransferExpirationTime(),
transferData.getExtendedRegistrationYears());
// Create speculative entities in anticipation of an automatic server approval.
ImmutableSet<TransferServerApproveEntity> serverApproveEntities =
createTransferServerApproveEntities(
transferData.getPendingTransferExpirationTime(),
domain.getRegistrationExpirationTime()
.plusYears(transferData.getExtendedRegistrationYears()),
historyEntry,
domain,
historyEntry.getTrid(),
transferData.getGainingClientId(),
transferCost,
transferData.getExtendedRegistrationYears(),
transferData.getTransferRequestTime());
transferData =
createPendingTransferData(transferData.asBuilder(), serverApproveEntities);
// Create a poll message to notify the losing registrar that a transfer was requested.
PollMessage requestPollMessage = createLosingTransferPollMessage(domain.getRepoId(),
transferData, transferData.getPendingTransferExpirationTime(), historyEntry)
.asBuilder().setEventTime(transferData.getTransferRequestTime()).build();
domain = domain.asBuilder().setTransferData(transferData).build();
autorenewBillingEvent = autorenewBillingEvent.asBuilder()
.setRecurrenceEndTime(transferData.getPendingTransferExpirationTime()).build();
autorenewPollMessage = autorenewPollMessage.asBuilder()
.setAutorenewEndTime(transferData.getPendingTransferExpirationTime()).build();
extraEntitiesToSave = new ImmutableSet.Builder<>()
.add(requestPollMessage)
.addAll(extraEntitiesToSave)
.addAll(serverApproveEntities).build();
} // End pending transfer check
ofy().save()
.entities(new ImmutableSet.Builder<>()
.add(domain, historyEntry, autorenewBillingEvent, autorenewPollMessage)
.addAll(extraEntitiesToSave)
.build())
.now();
}
});
// Record the number of domains imported

View file

@ -125,7 +125,7 @@ public class RdeHostImportAction implements Runnable {
@Override
public void vrun() {
HostResource host = XjcToHostResourceConverter.convert(xjcHost);
getImportUtils().importHost(host);
getImportUtils().importEppResource(host);
}
});
// Record number of hosts imported

View file

@ -16,34 +16,47 @@ package google.registry.rde.imports;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig.Config;
import google.registry.gcs.GcsUtils;
import google.registry.model.EppResource;
import google.registry.model.contact.ContactResource;
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainResource;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostResource;
import google.registry.model.index.EppResourceIndex;
import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.ofy.Ofy;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.RegistryNotFoundException;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.reporting.HistoryEntry;
import google.registry.util.Clock;
import google.registry.util.FormattingLogger;
import google.registry.xjc.XjcXmlTransformer;
import google.registry.xjc.rdedomain.XjcRdeDomain;
import google.registry.xjc.rdedomain.XjcRdeDomainElement;
import google.registry.xjc.rderegistrar.XjcRdeRegistrar;
import google.registry.xml.XmlException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
import javax.inject.Inject;
import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLStreamException;
import org.joda.time.DateTime;
/**
* Utility functions for escrow file import.
@ -66,10 +79,11 @@ public class RdeImportUtils {
this.escrowBucketName = escrowBucketName;
}
private <T extends EppResource> void importEppResource(final T resource, final String type) {
public <T extends EppResource & ForeignKeyedEppResource> ImmutableSet<Object>
createIndexesForEppResource(T resource) {
@SuppressWarnings("unchecked")
Class<T> resourceClass = (Class<T>) resource.getClass();
EppResource existing = ofy.load().key(Key.create(resource)).now();
Object existing = ofy.load().key(Key.create(resource)).now();
if (existing != null) {
// This will roll back the transaction and prevent duplicate history entries from being saved.
throw new ResourceExistsException();
@ -80,51 +94,30 @@ public class RdeImportUtils {
checkState(
existingForeignKeyIndex == null,
"New %s resource has existing foreign key index; foreignKey=%s, repoId=%s",
type,
resource.getClass().getCanonicalName(),
resource.getForeignKey(),
resource.getRepoId());
ofy.save().entity(resource);
ofy.save().entity(ForeignKeyIndex.create(resource, resource.getDeletionTime()));
ofy.save().entity(EppResourceIndex.create(Key.create(resource)));
logger.infofmt(
"Imported %s resource - ROID=%s, id=%s",
type, resource.getRepoId(), resource.getForeignKey());
return ImmutableSet.<Object>of(ForeignKeyIndex.create(resource, resource.getDeletionTime()),
EppResourceIndex.create(Key.create(resource)));
}
/**
* Imports a host from an escrow file.
* Imports a resource from an escrow file.
*
* <p>The host will only be imported if it has not been previously imported.
*
* <p>If the host is imported, {@link ForeignKeyIndex} and {@link EppResourceIndex} are also
* created.
*/
public void importHost(final HostResource resource) {
importEppResource(resource, "host");
}
/**
* Imports a contact from an escrow file.
*
* <p>The contact will only be imported if it has not been previously imported.
*
* <p>If the contact is imported, {@link ForeignKeyIndex} and {@link EppResourceIndex} are also
* created.
*/
public void importContact(final ContactResource resource) {
importEppResource(resource, "contact");
}
/**
* Imports a domain from an escrow file.
*
* <p>The domain will only be imported if it has not been previously imported.
*
* <p>If the domain is imported, {@link ForeignKeyIndex} and {@link EppResourceIndex} are also
* created.
*/
public void importDomain(final DomainResource resource) {
importEppResource(resource, "domain");
public <T extends EppResource & ForeignKeyedEppResource> void
importEppResource(final T resource) {
ofy.save().entities(new ImmutableSet.Builder<>()
.add(resource)
.addAll(createIndexesForEppResource(resource))
.build());
logger.infofmt(
"Imported %s resource - ROID=%s, id=%s",
resource.getClass().getCanonicalName(), resource.getRepoId(), resource.getForeignKey());
}
/**
@ -184,4 +177,59 @@ public class RdeImportUtils {
return Trid.create(
"Import_" + BaseEncoding.base64().encode(UUID.randomUUID().toString().getBytes()));
}
public static BillingEvent.Recurring createAutoRenewBillingEventForDomainImport(
XjcRdeDomain domain, HistoryEntry historyEntry) {
final BillingEvent.Recurring billingEvent =
new BillingEvent.Recurring.Builder()
.setReason(Reason.RENEW)
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setTargetId(domain.getRoid())
.setClientId(domain.getClID())
.setEventTime(domain.getExDate())
.setRecurrenceEndTime(END_OF_TIME)
.setParent(historyEntry)
.build();
return billingEvent;
}
public static PollMessage.Autorenew createAutoRenewPollMessageForDomainImport(
XjcRdeDomain domain, HistoryEntry historyEntry) {
final PollMessage.Autorenew pollMessage =
new PollMessage.Autorenew.Builder()
.setTargetId(domain.getRoid())
.setClientId(domain.getClID())
.setEventTime(domain.getExDate())
.setMsg("Domain was auto-renewed.")
.setParent(historyEntry)
.build();
return pollMessage;
}
public static HistoryEntry createHistoryEntryForDomainImport(XjcRdeDomain domain) {
XjcRdeDomainElement element = new XjcRdeDomainElement(domain);
final HistoryEntry historyEntry =
new HistoryEntry.Builder()
.setType(HistoryEntry.Type.RDE_IMPORT)
.setClientId(domain.getClID())
.setTrid(generateTridForImport())
.setModificationTime(DateTime.now())
.setXmlBytes(getObjectXml(element))
.setBySuperuser(true)
.setReason("RDE Import")
.setRequestedByRegistrar(false)
.setParent(Key.create(null, DomainResource.class, domain.getRoid()))
.build();
return historyEntry;
}
public static byte[] getObjectXml(Object jaxbElement) {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
XjcXmlTransformer.marshalLenient(jaxbElement, bout, UTF_8);
return bout.toByteArray();
} catch (XmlException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -17,9 +17,6 @@ package google.registry.rde.imports;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.transform;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.rde.imports.RdeImportUtils.generateTridForImport;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
@ -29,10 +26,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.net.InternetDomainName;
import com.googlecode.objectify.Key;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainAuthInfo;
@ -47,7 +41,6 @@ import google.registry.model.index.ForeignKeyIndex;
import google.registry.model.poll.PollMessage;
import google.registry.model.registry.Registries;
import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.util.NonFinalForTesting;
@ -67,6 +60,7 @@ import java.security.ProviderException;
import java.security.SecureRandom;
import java.util.Random;
import org.joda.time.DateTime;
import org.joda.time.Years;
/** Utility class that converts an {@link XjcRdeDomainElement} into a {@link DomainResource}. */
final class XjcToDomainResourceConverter extends XjcToEppResourceConverter {
@ -184,14 +178,10 @@ final class XjcToDomainResourceConverter extends XjcToEppResourceConverter {
}
/** Converts {@link XjcRdeDomain} to {@link DomainResource}. */
static DomainResource convertDomain(XjcRdeDomain domain) {
// First create history entry and autorenew billing event/poll message
// Autorenew billing event is required for creating AUTO_RENEW grace period
HistoryEntry historyEntry = createHistoryEntry(domain);
BillingEvent.Recurring autoRenewBillingEvent =
createAutoRenewBillingEvent(domain, historyEntry);
PollMessage.Autorenew pollMessage = createAutoRenewPollMessage(domain, historyEntry);
ofy().save().<ImmutableObject>entities(historyEntry, autoRenewBillingEvent, pollMessage);
static DomainResource convertDomain(
XjcRdeDomain domain,
BillingEvent.Recurring autoRenewBillingEvent,
PollMessage.Autorenew autoRenewPollMessage) {
GracePeriodConverter gracePeriodConverter =
new GracePeriodConverter(domain, Key.create(autoRenewBillingEvent));
DomainResource.Builder builder =
@ -202,7 +192,7 @@ final class XjcToDomainResourceConverter extends XjcToEppResourceConverter {
.setCurrentSponsorClientId(domain.getClID())
.setCreationClientId(domain.getCrRr().getValue())
.setCreationTime(domain.getCrDate())
.setAutorenewPollMessage(Key.create(pollMessage))
.setAutorenewPollMessage(Key.create(autoRenewPollMessage))
.setAutorenewBillingEvent(Key.create(autoRenewBillingEvent))
.setRegistrationExpirationTime(domain.getExDate())
.setLastEppUpdateTime(domain.getUpDate())
@ -218,7 +208,7 @@ final class XjcToDomainResourceConverter extends XjcToEppResourceConverter {
? ImmutableSet.<DelegationSignerData>of()
: ImmutableSet.copyOf(
transform(domain.getSecDNS().getDsDatas(), SECDNS_CONVERTER)))
.setTransferData(convertDomainTransferData(domain.getTrnData()))
.setTransferData(convertDomainTransferData(domain.getTrnData(), domain.getExDate()))
// authInfo pw must be a token between 6 and 16 characters in length
// generate a token of 16 characters as the default authInfo pw
.setAuthInfo(DomainAuthInfo
@ -229,51 +219,6 @@ final class XjcToDomainResourceConverter extends XjcToEppResourceConverter {
return builder.build();
}
private static BillingEvent.Recurring createAutoRenewBillingEvent(
XjcRdeDomain domain, HistoryEntry historyEntry) {
final BillingEvent.Recurring billingEvent =
new BillingEvent.Recurring.Builder()
.setReason(Reason.RENEW)
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setTargetId(domain.getRoid())
.setClientId(domain.getClID())
.setEventTime(domain.getExDate())
.setRecurrenceEndTime(END_OF_TIME)
.setParent(historyEntry)
.build();
return billingEvent;
}
private static PollMessage.Autorenew createAutoRenewPollMessage(
XjcRdeDomain domain, HistoryEntry historyEntry) {
final PollMessage.Autorenew pollMessage =
new PollMessage.Autorenew.Builder()
.setTargetId(domain.getRoid())
.setClientId(domain.getClID())
.setEventTime(domain.getExDate())
.setMsg("Domain was auto-renewed.")
.setParent(historyEntry)
.build();
return pollMessage;
}
private static HistoryEntry createHistoryEntry(XjcRdeDomain domain) {
XjcRdeDomainElement element = new XjcRdeDomainElement(domain);
final HistoryEntry historyEntry =
new HistoryEntry.Builder()
.setType(HistoryEntry.Type.RDE_IMPORT)
.setClientId(domain.getClID())
.setTrid(generateTridForImport())
.setModificationTime(DateTime.now())
.setXmlBytes(getObjectXml(element))
.setBySuperuser(true)
.setReason("RDE Import")
.setRequestedByRegistrar(false)
.setParent(Key.create(null, DomainResource.class, domain.getRoid()))
.build();
return historyEntry;
}
/** Returns {@link Key} for registrant from foreign key */
private static Key<ContactResource> convertRegistrant(String contactId) {
Key<ContactResource> key =
@ -296,16 +241,34 @@ final class XjcToDomainResourceConverter extends XjcToEppResourceConverter {
}
/** Converts {@link XjcRdeDomainTransferDataType} to {@link TransferData}. */
private static TransferData convertDomainTransferData(XjcRdeDomainTransferDataType data) {
private static TransferData convertDomainTransferData(XjcRdeDomainTransferDataType data,
DateTime domainExpiration) {
if (data == null) {
return TransferData.EMPTY;
}
// If the transfer is pending, calculate the number of years to add to the domain expiration
// on approval of the transfer.
TransferStatus transferStatus = TRANSFER_STATUS_MAPPER.xmlToEnum(data.getTrStatus().value());
// Get new expiration date
DateTime newExpirationTime = domainExpiration;
if (transferStatus == TransferStatus.PENDING) {
// Default to domain expiration time plus one year if no expiration is specified
if (data.getExDate() == null) {
newExpirationTime = newExpirationTime.plusYears(1);
} else {
newExpirationTime = data.getExDate();
}
}
return new TransferData.Builder()
.setTransferStatus(TRANSFER_STATUS_MAPPER.xmlToEnum(data.getTrStatus().value()))
.setTransferStatus(transferStatus)
.setGainingClientId(data.getReRr().getValue())
.setLosingClientId(data.getAcRr().getValue())
.setTransferRequestTime(data.getReDate())
.setPendingTransferExpirationTime(data.getAcDate())
// This will be wrong for domains that are not in pending transfer,
// but there isn't a reliable way to calculate it.
.setExtendedRegistrationYears(
Years.yearsBetween(domainExpiration, newExpirationTime).getYears())
.build();
}

View file

@ -31,6 +31,7 @@ java_library(
"@com_google_truth",
"@joda_time",
"@junit",
"@org_joda_money",
"@org_mockito_all",
],
)

View file

@ -18,11 +18,15 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.getHistoryEntries;
import static google.registry.testing.DatastoreHelper.getPollMessages;
import static google.registry.testing.DatastoreHelper.newDomainResource;
import static google.registry.testing.DatastoreHelper.persistActiveContact;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.DatastoreHelper.persistSimpleResource;
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static org.joda.money.CurrencyUnit.USD;
import static org.junit.Assert.fail;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsService;
@ -35,9 +39,13 @@ import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.gcs.GcsUtils;
import google.registry.mapreduce.MapreduceRunner;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.Trid;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferStatus;
import google.registry.request.Response;
import google.registry.testing.FakeResponse;
import google.registry.testing.mapreduce.MapreduceTestCase;
@ -45,7 +53,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.annotation.Nullable;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -56,6 +67,8 @@ import org.mockito.runners.MockitoJUnitRunner;
public class RdeDomainImportActionTest extends MapreduceTestCase<RdeDomainImportAction> {
private static final ByteSource DEPOSIT_1_DOMAIN = RdeImportsTestData.get("deposit_1_domain.xml");
private static final ByteSource DEPOSIT_1_DOMAIN_PENDING_TRANSFER =
RdeImportsTestData.get("deposit_1_domain_pending_transfer.xml");
private static final String IMPORT_BUCKET_NAME = "import-bucket";
private static final String IMPORT_FILE_NAME = "escrow-file.xml";
@ -82,7 +95,7 @@ public class RdeDomainImportActionTest extends MapreduceTestCase<RdeDomainImport
}
@Test
public void test_mapreduceSuccessfullyImportsDomain() throws Exception {
public void testMapreduceSuccessfullyImportsDomain() throws Exception {
pushToGcs(DEPOSIT_1_DOMAIN);
runMapreduce();
List<DomainResource> domains = ofy().load().type(DomainResource.class).list();
@ -91,7 +104,7 @@ public class RdeDomainImportActionTest extends MapreduceTestCase<RdeDomainImport
}
@Test
public void test_mapreduceSuccessfullyCreatesHistoryEntry() throws Exception {
public void testMapreduceSuccessfullyCreatesHistoryEntry() throws Exception {
pushToGcs(DEPOSIT_1_DOMAIN);
runMapreduce();
List<DomainResource> domains = ofy().load().type(DomainResource.class).list();
@ -104,7 +117,7 @@ public class RdeDomainImportActionTest extends MapreduceTestCase<RdeDomainImport
/** Ensures that a second pass on a domain does not import a new domain. */
@Test
public void test_mapreduceTwiceDoesNotDuplicateResources() throws Exception {
public void testMapreduceTwiceDoesNotDuplicateResources() throws Exception {
pushToGcs(DEPOSIT_1_DOMAIN);
// Create domain and history entry first
DomainResource existingDomain =
@ -135,8 +148,147 @@ public class RdeDomainImportActionTest extends MapreduceTestCase<RdeDomainImport
assertDnsTasksEnqueued("example1.test");
}
/**
* Verifies the state of an imported pending transfer before and after implicit server approval
*/
@Test
public void testMapreducePendingTransferServerApproval() throws Exception {
pushToGcs(DEPOSIT_1_DOMAIN_PENDING_TRANSFER);
runMapreduce();
List<DomainResource> domains = ofy().load().type(DomainResource.class).list();
assertThat(domains).hasSize(1);
checkDomain(domains.get(0));
// implicit server approval happens at 2015-01-08T22:00:00.0Z
DateTime serverApprovalTime = DateTime.parse("2015-01-08T22:00:00.0Z");
// Domain should be assigned to RegistrarX before server approval
DomainResource beforeApproval =
domains.get(0).cloneProjectedAtTime(serverApprovalTime.minus(Seconds.ONE));
assertThat(beforeApproval.getCurrentSponsorClientId()).isEqualTo("RegistrarX");
assertThat(loadAutorenewBillingEventForDomain(beforeApproval).getClientId())
.isEqualTo("RegistrarX");
assertThat(loadAutorenewPollMessageForDomain(beforeApproval).getClientId())
.isEqualTo("RegistrarX");
// Current expiration is 2015-04-03T22:00:00.0Z
assertThat(beforeApproval.getRegistrationExpirationTime())
.isEqualTo(DateTime.parse("2015-04-03T22:00:00.0Z"));
// Domain is not yet in transfer grace period
assertThat(beforeApproval.getGracePeriodStatuses()).doesNotContain(GracePeriodStatus.TRANSFER);
// Check autorenew events - recurrence end is set to transfer approval time,
// and client id is set to losing registrar. This is important in case the
// transfer is cancelled or rejected.
// Event time is set to domain expiration date.
checkAutorenewBillingEvent(
beforeApproval,
"RegistrarX",
DateTime.parse("2015-04-03T22:00:00.0Z"),
DateTime.parse("2015-01-08T22:00:00.0Z"));
checkAutorenewPollMessage(
beforeApproval,
"RegistrarX",
DateTime.parse("2015-04-03T22:00:00.0Z"),
DateTime.parse("2015-01-08T22:00:00.0Z"));
// Domain should be assigned to RegistrarY after server approval
DomainResource afterApproval =
domains.get(0).cloneProjectedAtTime(serverApprovalTime.plus(Seconds.ONE));
assertThat(afterApproval.getCurrentSponsorClientId()).isEqualTo("RegistrarY");
assertThat(loadAutorenewBillingEventForDomain(afterApproval).getClientId())
.isEqualTo("RegistrarY");
assertThat(loadAutorenewPollMessageForDomain(afterApproval).getClientId())
.isEqualTo("RegistrarY");
// New expiration should be incremented by 1 year
assertThat(afterApproval.getRegistrationExpirationTime())
.isEqualTo(DateTime.parse("2016-04-03T22:00:00.0Z"));
// Domain should now be in transfer grace period
assertThat(afterApproval.getGracePeriodStatuses()).contains(GracePeriodStatus.TRANSFER);
// Check autorenew events - recurrence end is set to END_OF_TIME,
// and client id is set to gaining registrar. This represents the new state of the domain,
// unless the transfer is cancelled during the grace period, at which time it will
// revert to the previous state.
// Event time is set to domain expiration date.
checkAutorenewBillingEvent(
afterApproval, "RegistrarY", DateTime.parse("2016-04-03T22:00:00.0Z"), END_OF_TIME);
checkAutorenewPollMessage(
afterApproval, "RegistrarY", DateTime.parse("2016-04-03T22:00:00.0Z"), END_OF_TIME);
}
@Test
public void testMapreducePendingTransferEvents() throws Exception {
pushToGcs(DEPOSIT_1_DOMAIN_PENDING_TRANSFER);
runMapreduce();
List<DomainResource> domains = ofy().load().type(DomainResource.class).list();
assertThat(domains).hasSize(1);
checkDomain(domains.get(0));
checkTransferRequestPollMessage(domains.get(0), "RegistrarX",
DateTime.parse("2015-01-03T22:00:00.0Z"));
checkTransferServerApprovalPollMessage(domains.get(0), "RegistrarX",
DateTime.parse("2015-01-08T22:00:00.0Z"));
checkTransferServerApprovalPollMessage(domains.get(0), "RegistrarY",
DateTime.parse("2015-01-08T22:00:00.0Z"));
// Billing event is set to the end of the transfer grace period, 5 days after server approval
checkTransferBillingEvent(domains.get(0), DateTime.parse("2015-01-13T22:00:00.0Z"));
}
private static void checkTransferBillingEvent(
DomainResource domain, DateTime automaticTransferTime) {
for (BillingEvent.OneTime event :
ofy().load().type(BillingEvent.OneTime.class).ancestor(domain).list()) {
if (event.getReason() == BillingEvent.Reason.TRANSFER) {
assertThat(event.getCost()).isEqualTo(Money.of(USD, 11));
assertThat(event.getClientId()).isEqualTo("RegistrarY");
assertThat(event.getBillingTime()).isEqualTo(automaticTransferTime);
}
}
}
/** Verifies the existence of a transfer request poll message */
private static void checkTransferRequestPollMessage(
DomainResource domain, String clientId, DateTime expectedAt) {
for (PollMessage message : getPollMessages(domain)) {
if (TransferStatus.PENDING.getMessage().equals(message.getMsg())
&& clientId.equals(message.getClientId())
&& expectedAt.equals(message.getEventTime())) {
return;
}
}
fail("Expected transfer request poll message");
}
/** Verifies the existence of a transfer request poll message */
private static void checkTransferServerApprovalPollMessage(
DomainResource domain, String clientId, DateTime expectedAt) {
for (PollMessage message : getPollMessages(domain)) {
if (TransferStatus.SERVER_APPROVED.getMessage().equals(message.getMsg())
&& clientId.equals(message.getClientId())
&& expectedAt.equals(message.getEventTime())) {
return;
}
}
fail("Expected transfer request poll message");
}
/** Verifies autorenew {@link PollMessage} is correct */
private static void checkAutorenewPollMessage(
DomainResource domain, String clientId, DateTime expectedAt, DateTime recurrenceEndTime) {
PollMessage.Autorenew autorenewPollMessage = loadAutorenewPollMessageForDomain(domain);
assertThat(autorenewPollMessage).isNotNull();
assertThat(autorenewPollMessage.getClientId()).isEqualTo(clientId);
assertThat(autorenewPollMessage.getEventTime()).isEqualTo(expectedAt);
assertThat(autorenewPollMessage.getAutorenewEndTime()).isEqualTo(recurrenceEndTime);
}
/** Verifies autorenew {@link BillingEvent} is correct */
private static void checkAutorenewBillingEvent(
DomainResource domain, String clientId, DateTime expectedAt, DateTime recurrenceEndTime) {
BillingEvent.Recurring autorenewBillingEvent = loadAutorenewBillingEventForDomain(domain);
assertThat(autorenewBillingEvent).isNotNull();
assertThat(autorenewBillingEvent.getClientId()).isEqualTo(clientId);
assertThat(autorenewBillingEvent.getEventTime()).isEqualTo(expectedAt);
assertThat(autorenewBillingEvent.getRecurrenceEndTime()).isEqualTo(recurrenceEndTime);
}
/** Verify history entry fields are correct */
private void checkHistoryEntry(HistoryEntry entry, DomainResource parent) {
private static void checkHistoryEntry(HistoryEntry entry, DomainResource parent) {
assertThat(entry.getType()).isEqualTo(HistoryEntry.Type.RDE_IMPORT);
assertThat(entry.getClientId()).isEqualTo(parent.getCurrentSponsorClientId());
assertThat(entry.getXmlBytes().length).isGreaterThan(0);
@ -146,8 +298,8 @@ public class RdeDomainImportActionTest extends MapreduceTestCase<RdeDomainImport
assertThat(entry.getParent()).isEqualTo(Key.create(parent));
}
/** Verifies that domain id and ROID match expected values */
private void checkDomain(DomainResource domain) {
/** Verifies that domain fields match expected values */
private static void checkDomain(DomainResource domain) {
assertThat(domain.getFullyQualifiedDomainName()).isEqualTo("example1.test");
assertThat(domain.getRepoId()).isEqualTo("Dexample1-TEST");
}
@ -174,6 +326,16 @@ public class RdeDomainImportActionTest extends MapreduceTestCase<RdeDomainImport
return result;
}
@Nullable
private static BillingEvent.Recurring loadAutorenewBillingEventForDomain(DomainResource domain) {
return ofy().load().key(domain.getAutorenewBillingEvent()).now();
}
@Nullable
private static PollMessage.Autorenew loadAutorenewPollMessageForDomain(DomainResource domain) {
return ofy().load().key(domain.getAutorenewPollMessage()).now();
}
private static HistoryEntry createHistoryEntry(String roid, String clid, byte[] objectXml) {
return new HistoryEntry.Builder()
.setType(HistoryEntry.Type.RDE_IMPORT)

View file

@ -114,7 +114,7 @@ public class RdeImportUtilsTest extends ShardableTestCase {
ofy().transact(new VoidWork() {
@Override
public void vrun() {
rdeImportUtils.importContact(newContact);
rdeImportUtils.importEppResource(newContact);
}});
assertEppResourceIndexEntityFor(newContact);
assertForeignKeyIndexFor(newContact);
@ -141,7 +141,7 @@ public class RdeImportUtilsTest extends ShardableTestCase {
ofy().transact(new VoidWork() {
@Override
public void vrun() {
rdeImportUtils.importContact(updatedContact);
rdeImportUtils.importEppResource(updatedContact);
}});
fail("Expected ResourceExistsException");
} catch (ResourceExistsException expected) {
@ -161,7 +161,7 @@ public class RdeImportUtilsTest extends ShardableTestCase {
ofy().transact(new VoidWork() {
@Override
public void vrun() {
rdeImportUtils.importHost(newHost);
rdeImportUtils.importEppResource(newHost);
}});
assertEppResourceIndexEntityFor(newHost);
@ -189,7 +189,7 @@ public class RdeImportUtilsTest extends ShardableTestCase {
ofy().transact(new VoidWork() {
@Override
public void vrun() {
rdeImportUtils.importHost(updatedHost);
rdeImportUtils.importEppResource(updatedHost);
}});
fail("Expected ResourceExistsException");
} catch (ResourceExistsException expected) {
@ -208,7 +208,7 @@ public class RdeImportUtilsTest extends ShardableTestCase {
ofy().transact(new VoidWork() {
@Override
public void vrun() {
rdeImportUtils.importDomain(newDomain);
rdeImportUtils.importEppResource(newDomain);
}
});
@ -236,7 +236,7 @@ public class RdeImportUtilsTest extends ShardableTestCase {
ofy().transact(new VoidWork() {
@Override
public void vrun() {
rdeImportUtils.importDomain(updatedDomain);
rdeImportUtils.importEppResource(updatedDomain);
}});
fail("Expected ResourceExistsException");
} catch (ResourceExistsException expected) {

View file

@ -18,6 +18,9 @@ import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.rde.imports.RdeImportTestUtils.checkTrid;
import static google.registry.rde.imports.RdeImportUtils.createAutoRenewBillingEventForDomainImport;
import static google.registry.rde.imports.RdeImportUtils.createAutoRenewPollMessageForDomainImport;
import static google.registry.rde.imports.RdeImportUtils.createHistoryEntryForDomainImport;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.getHistoryEntries;
import static google.registry.testing.DatastoreHelper.persistActiveContact;
@ -44,6 +47,7 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource;
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferStatus;
import google.registry.testing.AppEngineRule;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.ExceptionRule;
@ -368,12 +372,69 @@ public class XjcToDomainResourceConverterTest {
assertThat(pollMessage.getMsg()).isEqualTo("Domain was auto-renewed.");
}
@Test
public void testConvertDomainResourcePendingTransfer() throws Exception {
persistActiveContact("jd1234");
persistActiveContact("sh8013");
final XjcRdeDomain xjcDomain = loadDomainFromRdeXml("domain_fragment_pending_transfer.xml");
DomainResource domain = persistResource(convertDomainInTransaction(xjcDomain));
assertThat(domain.getTransferData()).isNotNull();
assertThat(domain.getTransferData().getTransferStatus()).isEqualTo(TransferStatus.PENDING);
assertThat(domain.getTransferData().getGainingClientId()).isEqualTo("RegistrarY");
assertThat(domain.getTransferData().getTransferRequestTime())
.isEqualTo(DateTime.parse("2015-01-03T22:00:00.0Z"));
assertThat(domain.getTransferData().getLosingClientId()).isEqualTo("RegistrarX");
assertThat(domain.getTransferData().getPendingTransferExpirationTime())
.isEqualTo(DateTime.parse("2015-01-08T22:00:00.0Z"));
}
@Test
public void testConvertDomainResourcePendingTransferDefaultExtendedYears() throws Exception {
persistActiveContact("jd1234");
persistActiveContact("sh8013");
final XjcRdeDomain xjcDomain = loadDomainFromRdeXml("domain_fragment_pending_transfer.xml");
DomainResource domain = persistResource(convertDomainInTransaction(xjcDomain));
assertThat(domain.getTransferData()).isNotNull();
assertThat(domain.getTransferData().getExtendedRegistrationYears()).isEqualTo(1);
}
@Test
public void testConvertDomainResourcePendingTransferExtendOneYear() throws Exception {
persistActiveContact("jd1234");
persistActiveContact("sh8013");
final XjcRdeDomain xjcDomain = loadDomainFromRdeXml("domain_fragment_pending_transfer_1yr.xml");
DomainResource domain = persistResource(convertDomainInTransaction(xjcDomain));
assertThat(domain.getTransferData()).isNotNull();
assertThat(domain.getTransferData().getExtendedRegistrationYears()).isEqualTo(1);
}
@Test
public void testConvertDomainResourcePendingTransferExtendTwoYears() throws Exception {
persistActiveContact("jd1234");
persistActiveContact("sh8013");
final XjcRdeDomain xjcDomain = loadDomainFromRdeXml("domain_fragment_pending_transfer_2yr.xml");
DomainResource domain = persistResource(convertDomainInTransaction(xjcDomain));
assertThat(domain.getTransferData()).isNotNull();
assertThat(domain.getTransferData().getExtendedRegistrationYears()).isEqualTo(2);
}
private static DomainResource convertDomainInTransaction(final XjcRdeDomain xjcDomain) {
return ofy().transact(new Work<DomainResource>() {
@Override
public DomainResource run() {
return XjcToDomainResourceConverter.convertDomain(xjcDomain);
}});
final HistoryEntry historyEntry = createHistoryEntryForDomainImport(xjcDomain);
final BillingEvent.Recurring autorenewBillingEvent =
createAutoRenewBillingEventForDomainImport(xjcDomain, historyEntry);
final PollMessage.Autorenew autorenewPollMessage =
createAutoRenewPollMessageForDomainImport(xjcDomain, historyEntry);
return ofy()
.transact(
new Work<DomainResource>() {
@SuppressWarnings("unchecked")
@Override
public DomainResource run() {
ofy().save().entities(historyEntry, autorenewBillingEvent, autorenewPollMessage);
return XjcToDomainResourceConverter.convertDomain(
xjcDomain, autorenewBillingEvent, autorenewPollMessage);
}
});
}
private XjcRdeDomain loadDomainFromRdeXml(String filename) {

View file

@ -0,0 +1,249 @@
<?xml version="1.0" encoding="UTF-8"?>
<rde:deposit type="FULL" id="20101017001" prevId="20101010001"
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0"
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0"
xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1"
xmlns:rde="urn:ietf:params:xml:ns:rde-1.0"
xmlns:rdeHeader="urn:ietf:params:xml:ns:rdeHeader-1.0"
xmlns:rdeDom="urn:ietf:params:xml:ns:rdeDomain-1.0"
xmlns:rdeHost="urn:ietf:params:xml:ns:rdeHost-1.0"
xmlns:rdeContact="urn:ietf:params:xml:ns:rdeContact-1.0"
xmlns:rdeRegistrar="urn:ietf:params:xml:ns:rdeRegistrar-1.0"
xmlns:rdeIDN="urn:ietf:params:xml:ns:rdeIDN-1.0"
xmlns:rdeNNDN="urn:ietf:params:xml:ns:rdeNNDN-1.0"
xmlns:rdeEppParams="urn:ietf:params:xml:ns:rdeEppParams-1.0"
xmlns:rdePolicy="urn:ietf:params:xml:ns:rdePolicy-1.0"
xmlns:epp="urn:ietf:params:xml:ns:epp-1.0">
<rde:watermark>2010-10-17T00:00:00Z</rde:watermark>
<rde:rdeMenu>
<rde:version>1.0</rde:version>
<rde:objURI>urn:ietf:params:xml:ns:rdeHeader-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeContact-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeHost-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeDomain-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeRegistrar-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeIDN-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeNNDN-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeEppParams-1.0</rde:objURI>
</rde:rdeMenu>
<!-- Contents -->
<rde:contents>
<!-- Header -->
<rdeHeader:header>
<rdeHeader:tld>test</rdeHeader:tld>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeDomain-1.0">2
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeHost-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeContact-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeRegistrar-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeIDN-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeNNDN-1.0">1
</rdeHeader:count>
<rdeHeader:count
uri="urn:ietf:params:xml:ns:rdeEppParams-1.0">1
</rdeHeader:count>
</rdeHeader:header>
<!-- Domain: example1.test -->
<rdeDom:domain>
<rdeDom:name>example1.test</rdeDom:name>
<rdeDom:roid>Dexample1-TEST</rdeDom:roid>
<rdeDom:status s="ok"/>
<rdeDom:registrant>jd1234</rdeDom:registrant>
<rdeDom:contact type="admin">sh8013</rdeDom:contact>
<rdeDom:contact type="tech">sh8013</rdeDom:contact>
<rdeDom:clID>RegistrarX</rdeDom:clID>
<rdeDom:crRr client="jdoe">RegistrarX</rdeDom:crRr>
<rdeDom:crDate>1999-04-03T22:00:00.0Z</rdeDom:crDate>
<rdeDom:exDate>2015-04-03T22:00:00.0Z</rdeDom:exDate>
<rdeDom:upRr>RegistrarY</rdeDom:upRr>
<rdeDom:upDate>2015-01-03T22:00:00.0Z</rdeDom:upDate>
<rdeDom:trnData>
<rdeDom:trStatus>pending</rdeDom:trStatus>
<rdeDom:reRr>RegistrarY</rdeDom:reRr>
<rdeDom:reDate>2015-01-03T22:00:00.0Z</rdeDom:reDate>
<rdeDom:acRr>RegistrarX</rdeDom:acRr>
<rdeDom:acDate>2015-01-08T22:00:00.0Z</rdeDom:acDate>
</rdeDom:trnData>
</rdeDom:domain>
<!-- Host: ns1.example.com -->
<rdeHost:host>
<rdeHost:name>ns1.example.com</rdeHost:name>
<rdeHost:roid>Hns1_example_com-TEST</rdeHost:roid>
<rdeHost:status s="ok"/>
<rdeHost:status s="linked"/>
<rdeHost:addr ip="v4">192.0.2.2</rdeHost:addr>
<rdeHost:addr ip="v4">192.0.2.29</rdeHost:addr>
<rdeHost:addr ip="v6">1080:0:0:0:8:800:200C:417A
</rdeHost:addr>
<rdeHost:clID>RegistrarX</rdeHost:clID>
<rdeHost:crRr>RegistrarX</rdeHost:crRr>
<rdeHost:crDate>1999-05-08T12:10:00.0Z</rdeHost:crDate>
<rdeHost:upRr>RegistrarX</rdeHost:upRr>
<rdeHost:upDate>2009-10-03T09:34:00.0Z</rdeHost:upDate>
</rdeHost:host>
<!-- Host: ns1.example1.test -->
<rdeHost:host>
<rdeHost:name>ns1.example1.test</rdeHost:name>
<rdeHost:roid>Hns1_example1_test-TEST</rdeHost:roid>
<rdeHost:status s="ok"/>
<rdeHost:status s="linked"/>
<rdeHost:addr ip="v4">192.0.2.2</rdeHost:addr>
<rdeHost:addr ip="v4">192.0.2.29</rdeHost:addr>
<rdeHost:addr ip="v6">1080:0:0:0:8:800:200C:417A
</rdeHost:addr>
<rdeHost:clID>RegistrarX</rdeHost:clID>
<rdeHost:crRr>RegistrarX</rdeHost:crRr>
<rdeHost:crDate>1999-05-08T12:10:00.0Z</rdeHost:crDate>
<rdeHost:upRr>RegistrarX</rdeHost:upRr>
<rdeHost:upDate>2009-10-03T09:34:00.0Z</rdeHost:upDate>
</rdeHost:host>
<!-- Contact: sh8013 -->
<rdeContact:contact>
<rdeContact:id>sh8013</rdeContact:id>
<rdeContact:roid>Csh8013-TEST</rdeContact:roid>
<rdeContact:status s="linked"/>
<rdeContact:status s="clientDeleteProhibited"/>
<rdeContact:postalInfo type="int">
<contact:name>John Doe</contact:name>
<contact:org>Example Inc.</contact:org>
<contact:addr>
<contact:street>123 Example Dr.</contact:street>
<contact:street>Suite 100</contact:street>
<contact:city>Dulles</contact:city>
<contact:sp>VA</contact:sp>
<contact:pc>20166-6503</contact:pc>
<contact:cc>US</contact:cc>
</contact:addr>
</rdeContact:postalInfo>
<rdeContact:voice x="1234">+1.7035555555
</rdeContact:voice>
<rdeContact:fax>+1.7035555556
</rdeContact:fax>
<rdeContact:email>jdoe@example.test
</rdeContact:email>
<rdeContact:clID>RegistrarX</rdeContact:clID>
<rdeContact:crRr client="jdoe">RegistrarX
</rdeContact:crRr>
<rdeContact:crDate>2009-09-13T08:01:00.0Z</rdeContact:crDate>
<rdeContact:upRr client="jdoe">RegistrarX
</rdeContact:upRr>
<rdeContact:upDate>2009-11-26T09:10:00.0Z</rdeContact:upDate>
<rdeContact:trDate>2009-12-03T09:05:00.0Z</rdeContact:trDate>
<rdeContact:disclose flag="0">
<contact:voice/>
<contact:email/>
</rdeContact:disclose>
</rdeContact:contact>
<!-- Registrar: RegistrarX -->
<rdeRegistrar:registrar>
<rdeRegistrar:id>RegistrarX</rdeRegistrar:id>
<rdeRegistrar:name>Registrar X</rdeRegistrar:name>
<rdeRegistrar:gurid>123</rdeRegistrar:gurid>
<rdeRegistrar:status>ok</rdeRegistrar:status>
<rdeRegistrar:postalInfo type="int">
<rdeRegistrar:addr>
<rdeRegistrar:street>123 Example Dr.
</rdeRegistrar:street>
<rdeRegistrar:street>Suite 100
</rdeRegistrar:street>
<rdeRegistrar:city>Dulles</rdeRegistrar:city>
<rdeRegistrar:sp>VA</rdeRegistrar:sp>
<rdeRegistrar:pc>20166-6503</rdeRegistrar:pc>
<rdeRegistrar:cc>US</rdeRegistrar:cc>
</rdeRegistrar:addr>
</rdeRegistrar:postalInfo>
<rdeRegistrar:voice x="1234">+1.7035555555
</rdeRegistrar:voice>
<rdeRegistrar:fax>+1.7035555556
</rdeRegistrar:fax>
<rdeRegistrar:email>jdoe@example.test
</rdeRegistrar:email>
<rdeRegistrar:url>http://www.example.test
</rdeRegistrar:url>
<rdeRegistrar:whoisInfo>
<rdeRegistrar:name>whois.example.test
</rdeRegistrar:name>
<rdeRegistrar:url>http://whois.example.test
</rdeRegistrar:url>
</rdeRegistrar:whoisInfo>
<rdeRegistrar:crDate>2005-04-23T11:49:00.0Z</rdeRegistrar:crDate>
<rdeRegistrar:upDate>2009-02-17T17:51:00.0Z</rdeRegistrar:upDate>
</rdeRegistrar:registrar>
<!-- IDN Table -->
<rdeIDN:idnTableRef id="pt-BR">
<rdeIDN:url>
http://www.iana.org/domains/idn-tables/tables/br_pt-br_1.0.html
</rdeIDN:url>
<rdeIDN:urlPolicy>
http://registro.br/dominio/regras.html
</rdeIDN:urlPolicy>
</rdeIDN:idnTableRef>
<!-- NNDN: pinguino.test -->
<rdeNNDN:NNDN>
<rdeNNDN:aName>xn--exampl-gva.test</rdeNNDN:aName>
<rdeNNDN:idnTableId>pt-BR</rdeNNDN:idnTableId>
<rdeNNDN:originalName>example1.test</rdeNNDN:originalName>
<rdeNNDN:nameState>withheld</rdeNNDN:nameState>
<rdeNNDN:crDate>2005-04-23T11:49:00.0Z</rdeNNDN:crDate>
</rdeNNDN:NNDN>
<!-- EppParams -->
<rdeEppParams:eppParams>
<rdeEppParams:version>1.0</rdeEppParams:version>
<rdeEppParams:lang>en</rdeEppParams:lang>
<rdeEppParams:objURI>
urn:ietf:params:xml:ns:domain-1.0
</rdeEppParams:objURI>
<rdeEppParams:objURI>
urn:ietf:params:xml:ns:contact-1.0
</rdeEppParams:objURI>
<rdeEppParams:objURI>
urn:ietf:params:xml:ns:host-1.0
</rdeEppParams:objURI>
<rdeEppParams:svcExtension>
<epp:extURI>urn:ietf:params:xml:ns:rgp-1.0
</epp:extURI>
<epp:extURI>urn:ietf:params:xml:ns:secDNS-1.1
</epp:extURI>
</rdeEppParams:svcExtension>
<rdeEppParams:dcp>
<epp:access><epp:all/></epp:access>
<epp:statement>
<epp:purpose>
<epp:admin/>
<epp:prov/>
</epp:purpose>
<epp:recipient>
<epp:ours/>
<epp:public/>
</epp:recipient>
<epp:retention>
<epp:stated/>
</epp:retention>
</epp:statement>
</rdeEppParams:dcp>
</rdeEppParams:eppParams>
<rdePolicy:policy
scope="//rde:deposit/rde:contents/rdeDomain:domain"
element="rdeDom:registrant" />
</rde:contents>
</rde:deposit>

View file

@ -0,0 +1,23 @@
<rdeDom:domain
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0"
xmlns:rdeDom="urn:ietf:params:xml:ns:rdeDomain-1.0">
<rdeDom:name>example1.example</rdeDom:name>
<rdeDom:roid>Dexample1-TEST</rdeDom:roid>
<rdeDom:status s="pendingTransfer"/>
<rdeDom:registrant>jd1234</rdeDom:registrant>
<rdeDom:contact type="admin">sh8013</rdeDom:contact>
<rdeDom:contact type="tech">sh8013</rdeDom:contact>
<rdeDom:clID>RegistrarX</rdeDom:clID>
<rdeDom:crRr client="jdoe">RegistrarX</rdeDom:crRr>
<rdeDom:crDate>1999-04-03T22:00:00.0Z</rdeDom:crDate>
<rdeDom:exDate>2015-04-03T22:00:00.0Z</rdeDom:exDate>
<rdeDom:upRr>RegistrarY</rdeDom:upRr>
<rdeDom:upDate>2015-01-03T22:00:00.0Z</rdeDom:upDate>
<rdeDom:trnData>
<rdeDom:trStatus>pending</rdeDom:trStatus>
<rdeDom:reRr>RegistrarY</rdeDom:reRr>
<rdeDom:reDate>2015-01-03T22:00:00.0Z</rdeDom:reDate>
<rdeDom:acRr>RegistrarX</rdeDom:acRr>
<rdeDom:acDate>2015-01-08T22:00:00.0Z</rdeDom:acDate>
</rdeDom:trnData>
</rdeDom:domain>

View file

@ -0,0 +1,24 @@
<rdeDom:domain
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0"
xmlns:rdeDom="urn:ietf:params:xml:ns:rdeDomain-1.0">
<rdeDom:name>example1.example</rdeDom:name>
<rdeDom:roid>Dexample1-TEST</rdeDom:roid>
<rdeDom:status s="pendingTransfer"/>
<rdeDom:registrant>jd1234</rdeDom:registrant>
<rdeDom:contact type="admin">sh8013</rdeDom:contact>
<rdeDom:contact type="tech">sh8013</rdeDom:contact>
<rdeDom:clID>RegistrarX</rdeDom:clID>
<rdeDom:crRr client="jdoe">RegistrarX</rdeDom:crRr>
<rdeDom:crDate>1999-04-03T22:00:00.0Z</rdeDom:crDate>
<rdeDom:exDate>2015-04-03T22:00:00.0Z</rdeDom:exDate>
<rdeDom:upRr>RegistrarY</rdeDom:upRr>
<rdeDom:upDate>2015-01-03T22:00:00.0Z</rdeDom:upDate>
<rdeDom:trnData>
<rdeDom:trStatus>pending</rdeDom:trStatus>
<rdeDom:reRr>RegistrarY</rdeDom:reRr>
<rdeDom:reDate>2015-01-03T22:00:00.0Z</rdeDom:reDate>
<rdeDom:acRr>RegistrarX</rdeDom:acRr>
<rdeDom:acDate>2015-01-08T22:00:00.0Z</rdeDom:acDate>
<rdeDom:exDate>2016-04-03T22:00:00.0Z</rdeDom:exDate>
</rdeDom:trnData>
</rdeDom:domain>

View file

@ -0,0 +1,24 @@
<rdeDom:domain
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0"
xmlns:rdeDom="urn:ietf:params:xml:ns:rdeDomain-1.0">
<rdeDom:name>example1.example</rdeDom:name>
<rdeDom:roid>Dexample1-TEST</rdeDom:roid>
<rdeDom:status s="pendingTransfer"/>
<rdeDom:registrant>jd1234</rdeDom:registrant>
<rdeDom:contact type="admin">sh8013</rdeDom:contact>
<rdeDom:contact type="tech">sh8013</rdeDom:contact>
<rdeDom:clID>RegistrarX</rdeDom:clID>
<rdeDom:crRr client="jdoe">RegistrarX</rdeDom:crRr>
<rdeDom:crDate>1999-04-03T22:00:00.0Z</rdeDom:crDate>
<rdeDom:exDate>2015-04-03T22:00:00.0Z</rdeDom:exDate>
<rdeDom:upRr>RegistrarY</rdeDom:upRr>
<rdeDom:upDate>2015-01-03T22:00:00.0Z</rdeDom:upDate>
<rdeDom:trnData>
<rdeDom:trStatus>pending</rdeDom:trStatus>
<rdeDom:reRr>RegistrarY</rdeDom:reRr>
<rdeDom:reDate>2015-01-03T22:00:00.0Z</rdeDom:reDate>
<rdeDom:acRr>RegistrarX</rdeDom:acRr>
<rdeDom:acDate>2015-01-08T22:00:00.0Z</rdeDom:acDate>
<rdeDom:exDate>2017-04-03T22:00:00.0Z</rdeDom:exDate>
</rdeDom:trnData>
</rdeDom:domain>