diff --git a/java/google/registry/config/ConfigModule.java b/java/google/registry/config/ConfigModule.java index c818bfb6e..66adc7c12 100644 --- a/java/google/registry/config/ConfigModule.java +++ b/java/google/registry/config/ConfigModule.java @@ -314,6 +314,15 @@ public final class ConfigModule { return projectId + "-rde"; } + /** + * Returns the Google Cloud Storage bucket for importing escrow files. + */ + @Provides + @Config("rdeImportBucket") + public String provideRdeImportBucket(@Config("projectId") String projectId) { + return projectId + "-rde-import"; + } + /** * Size of Ghostryde buffer in bytes for each layer in the pipeline. * diff --git a/java/google/registry/config/ProductionRegistryConfigExample.java b/java/google/registry/config/ProductionRegistryConfigExample.java index ccabf8735..20a688d2d 100644 --- a/java/google/registry/config/ProductionRegistryConfigExample.java +++ b/java/google/registry/config/ProductionRegistryConfigExample.java @@ -98,11 +98,6 @@ public final class ProductionRegistryConfigExample implements RegistryConfig { return getProjectId() + "-zonefiles"; } - @Override - public String getEscrowFileImportBucket() { - return getProjectId() + "-escrow-import"; - } - @Override public boolean getTmchCaTestingMode() { switch (environment) { diff --git a/java/google/registry/config/RegistryConfig.java b/java/google/registry/config/RegistryConfig.java index 85c2c57a8..c66ab572e 100644 --- a/java/google/registry/config/RegistryConfig.java +++ b/java/google/registry/config/RegistryConfig.java @@ -89,11 +89,6 @@ public interface RegistryConfig { */ public String getZoneFilesBucket(); - /** - * Returns the Google Cloud Storage bucket for importing escrow files. - */ - public String getEscrowFileImportBucket(); - /** * Returns {@code true} if TMCH certificate authority should be in testing mode. * diff --git a/java/google/registry/config/TestRegistryConfig.java b/java/google/registry/config/TestRegistryConfig.java index 3ec49256b..e01a140d7 100644 --- a/java/google/registry/config/TestRegistryConfig.java +++ b/java/google/registry/config/TestRegistryConfig.java @@ -65,11 +65,6 @@ public class TestRegistryConfig implements RegistryConfig { return getProjectId() + "-zonefiles"; } - @Override - public String getEscrowFileImportBucket() { - return getProjectId() + "-escrow-import"; - } - @Override public boolean getTmchCaTestingMode() { return true; diff --git a/java/google/registry/gcs/GcsUtils.java b/java/google/registry/gcs/GcsUtils.java index 554413ebb..97e70a485 100644 --- a/java/google/registry/gcs/GcsUtils.java +++ b/java/google/registry/gcs/GcsUtils.java @@ -35,7 +35,7 @@ import javax.annotation.CheckReturnValue; import javax.inject.Inject; /** Utilities for working with Google Cloud Storage. */ -public final class GcsUtils { +public class GcsUtils { private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); diff --git a/java/google/registry/rde/RdeImportUtils.java b/java/google/registry/rde/RdeImportUtils.java index c615997a7..4253909d0 100644 --- a/java/google/registry/rde/RdeImportUtils.java +++ b/java/google/registry/rde/RdeImportUtils.java @@ -14,17 +14,30 @@ package google.registry.rde; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import com.google.appengine.tools.cloudstorage.GcsFilename; import com.googlecode.objectify.Key; import com.googlecode.objectify.Work; +import google.registry.config.ConfigModule.Config; +import google.registry.gcs.GcsUtils; import google.registry.model.contact.ContactResource; import google.registry.model.index.EppResourceIndex; import google.registry.model.index.ForeignKeyIndex; import google.registry.model.ofy.Ofy; +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.util.Clock; import google.registry.util.FormattingLogger; +import google.registry.xjc.rderegistrar.XjcRdeRegistrar; +import java.io.IOException; +import java.io.InputStream; import javax.inject.Inject; +import javax.xml.stream.XMLStreamException; +import org.joda.time.DateTime; /** Utility functions for escrow file import. */ public final class RdeImportUtils { @@ -33,11 +46,16 @@ public final class RdeImportUtils { private final Ofy ofy; private final Clock clock; + private final String escrowBucketName; + private final GcsUtils gcsUtils; @Inject - public RdeImportUtils(Ofy ofy, Clock clock) { + public RdeImportUtils( + Ofy ofy, Clock clock, @Config("rdeImportBucket") String escrowBucketName, GcsUtils gcsUtils) { this.ofy = ofy; this.clock = clock; + this.gcsUtils = gcsUtils; + this.escrowBucketName = escrowBucketName; } /** @@ -84,4 +102,55 @@ public final class RdeImportUtils { } }); } + + /** + * Validates an escrow file for import. + * + *

Before an escrow file is imported into the registry, the following conditions must be met: + * + *

+ * + *

If any of the above conditions is not true, an {@link IllegalStateException} will be thrown. + * + * @param escrowFilePath Path to the escrow file to validate + * @throws IOException If the escrow file cannot be read + * @throws IllegalArgumentException if the escrow file cannot be imported + */ + public void validateEscrowFileForImport(String escrowFilePath) throws IOException { + // TODO (wolfgang): Add validation method for IDN tables + try (InputStream input = + gcsUtils.openInputStream(new GcsFilename(escrowBucketName, escrowFilePath))) { + try { + RdeParser parser = new RdeParser(input); + // validate that tld exists and is in PREDELEGATION state + String tld = parser.getHeader().getTld(); + try { + Registry registry = Registry.get(tld); + TldState currentState = registry.getTldState(DateTime.now()); + checkArgument( + currentState == TldState.PREDELEGATION, + String.format("Tld '%s' is in state %s and cannot be imported", tld, currentState)); + } catch (RegistryNotFoundException e) { + throw new IllegalArgumentException( + String.format("Tld '%s' not found in the registry", tld)); + } + // validate that all registrars exist + while (parser.nextRegistrar()) { + XjcRdeRegistrar registrar = parser.getRegistrar(); + if (Registrar.loadByClientId(registrar.getId()) == null) { + throw new IllegalArgumentException( + String.format("Registrar '%s' not found in the registry", registrar.getId())); + } + } + } catch (XMLStreamException e) { + throw new IllegalArgumentException( + String.format("Invalid XML file: '%s'", escrowFilePath), e); + } + } + } } diff --git a/javatests/google/registry/rde/RdeImportUtilsTest.java b/javatests/google/registry/rde/RdeImportUtilsTest.java index 92f933ca1..c5906f53b 100644 --- a/javatests/google/registry/rde/RdeImportUtilsTest.java +++ b/javatests/google/registry/rde/RdeImportUtilsTest.java @@ -16,36 +16,62 @@ package google.registry.rde; 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.persistNewRegistrar; import static google.registry.testing.DatastoreHelper.persistResource; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import com.google.appengine.tools.cloudstorage.GcsFilename; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; +import com.google.common.io.ByteSource; import com.googlecode.objectify.Key; import com.googlecode.objectify.Work; +import google.registry.gcs.GcsUtils; import google.registry.model.EppResource; import google.registry.model.contact.ContactResource; import google.registry.model.index.EppResourceIndex; import google.registry.model.index.EppResourceIndexBucket; import google.registry.model.index.ForeignKeyIndex; +import google.registry.model.registry.Registry.TldState; import google.registry.testing.AppEngineRule; +import google.registry.testing.ExceptionRule; import google.registry.testing.FakeClock; import google.registry.testing.ShardableTestCase; +import java.io.IOException; +import java.io.InputStream; import org.joda.time.DateTime; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; /** Unit tests for {@link RdeImportUtils} */ -@RunWith(JUnit4.class) +@RunWith(MockitoJUnitRunner.class) public class RdeImportUtilsTest extends ShardableTestCase { + private static final ByteSource DEPOSIT_XML = RdeTestData.get("deposit_full.xml"); + private static final ByteSource DEPOSIT_BADTLD_XML = RdeTestData.get("deposit_full_badtld.xml"); + private static final ByteSource DEPOSIT_GETLD_XML = RdeTestData.get("deposit_full_getld.xml"); + private static final ByteSource DEPOSIT_BADREGISTRAR_XML = + RdeTestData.get("deposit_full_badregistrar.xml"); + + private InputStream xmlInput; + @Rule - public final AppEngineRule appEngine = AppEngineRule.builder() - .withDatastore() - .build(); + public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build(); + + @Rule + public final ExceptionRule thrown = new ExceptionRule(); + + @Mock + private GcsUtils gcsUtils; private RdeImportUtils rdeImportUtils; private FakeClock clock; @@ -54,7 +80,17 @@ public class RdeImportUtilsTest extends ShardableTestCase { public void before() { clock = new FakeClock(); clock.setTo(DateTime.now()); - rdeImportUtils = new RdeImportUtils(ofy(), clock); + rdeImportUtils = new RdeImportUtils(ofy(), clock, "import-bucket", gcsUtils); + createTld("test", TldState.PREDELEGATION); + createTld("getld", TldState.GENERAL_AVAILABILITY); + persistNewRegistrar("RegistrarX", 1L); + } + + @After + public void after() throws IOException { + if (xmlInput != null) { + xmlInput.close(); + } } /** Verifies import of a contact that has not been previously imported */ @@ -78,9 +114,11 @@ public class RdeImportUtilsTest extends ShardableTestCase { public void testImportExistingContact() { ContactResource newContact = buildNewContact(); persistResource(newContact); - ContactResource updatedContact = newContact.asBuilder() - .setLastEppUpdateTime(newContact.getLastEppUpdateTime().plusSeconds(1)) - .build(); + ContactResource updatedContact = + newContact + .asBuilder() + .setLastEppUpdateTime(newContact.getLastEppUpdateTime().plusSeconds(1)) + .build(); assertThat(rdeImportUtils.importContact(updatedContact)).isFalse(); // verify the updated contact was saved @@ -100,27 +138,62 @@ public class RdeImportUtilsTest extends ShardableTestCase { .build(); } + /** Verifies that no errors are thrown when a valid escrow file is validated */ + @Test + public void testValidateEscrowFile_valid() throws Exception { + xmlInput = DEPOSIT_XML.openBufferedStream(); + when(gcsUtils.openInputStream(any(GcsFilename.class))).thenReturn(xmlInput); + rdeImportUtils.validateEscrowFileForImport("valid-deposit-file.xml"); + verify(gcsUtils).openInputStream(new GcsFilename("import-bucket", "valid-deposit-file.xml")); + } + + /** Verifies thrown error when tld in escrow file is not in the registry */ + @Test + public void testValidateEscrowFile_tldNotFound() throws Exception { + thrown.expect(IllegalArgumentException.class, "Tld 'badtld' not found in the registry"); + xmlInput = DEPOSIT_BADTLD_XML.openBufferedStream(); + when(gcsUtils.openInputStream(any(GcsFilename.class))).thenReturn(xmlInput); + rdeImportUtils.validateEscrowFileForImport("invalid-deposit-badtld.xml"); + } + + /** Verifies thrown errer when tld in escrow file is not in PREDELEGATION state */ + @Test + public void testValidateEscrowFile_tldWrongState() throws Exception { + thrown.expect( + IllegalArgumentException.class, + "Tld 'getld' is in state GENERAL_AVAILABILITY and cannot be imported"); + xmlInput = DEPOSIT_GETLD_XML.openBufferedStream(); + when(gcsUtils.openInputStream(any(GcsFilename.class))).thenReturn(xmlInput); + rdeImportUtils.validateEscrowFileForImport("invalid-deposit-getld.xml"); + } + + /** Verifies thrown error when registrar in escrow file is not in the registry */ + @Test + public void testValidateEscrowFile_badRegistrar() throws Exception { + thrown.expect( + IllegalArgumentException.class, "Registrar 'RegistrarY' not found in the registry"); + xmlInput = DEPOSIT_BADREGISTRAR_XML.openBufferedStream(); + when(gcsUtils.openInputStream(any(GcsFilename.class))).thenReturn(xmlInput); + rdeImportUtils.validateEscrowFileForImport("invalid-deposit-badregistrar.xml"); + } + + /** Gets the contact with the specified ROID */ private static ContactResource getContact(String repoId) { final Key key = Key.create(ContactResource.class, repoId); return ofy().transact(new Work() { - @Override public ContactResource run() { return ofy().load().key(key).now(); }}); } - /** - * Confirms that a ForeignKeyIndex exists in the datastore for a given resource. - */ + /** Confirms that a ForeignKeyIndex exists in the datastore for a given resource. */ private static void assertForeignKeyIndexFor(final T resource) { assertThat(ForeignKeyIndex.load(resource.getClass(), resource.getForeignKey(), DateTime.now())) .isNotNull(); } - /** - * Confirms that an EppResourceIndex entity exists in datastore for a given resource. - */ + /** Confirms that an EppResourceIndex entity exists in datastore for a given resource. */ private static void assertEppResourceIndexEntityFor(final T resource) { ImmutableList indices = FluentIterable .from(ofy().load() diff --git a/javatests/google/registry/rde/testdata/deposit_full_badregistrar.xml b/javatests/google/registry/rde/testdata/deposit_full_badregistrar.xml new file mode 100644 index 000000000..17d6f183d --- /dev/null +++ b/javatests/google/registry/rde/testdata/deposit_full_badregistrar.xml @@ -0,0 +1,259 @@ + + + + 2010-10-17T00:00:00Z + + 1.0 + urn:ietf:params:xml:ns:rdeHeader-1.0 + urn:ietf:params:xml:ns:rdeContact-1.0 + urn:ietf:params:xml:ns:rdeHost-1.0 + urn:ietf:params:xml:ns:rdeDomain-1.0 + urn:ietf:params:xml:ns:rdeRegistrar-1.0 + urn:ietf:params:xml:ns:rdeIDN-1.0 + urn:ietf:params:xml:ns:rdeNNDN-1.0 + urn:ietf:params:xml:ns:rdeEppParams-1.0 + + + + + + + test + 2 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + + + + + example1.test + Dexample1-TEST + + jd1234 + sh8013 + sh8013 + + ns1.example.com + ns1.example1.test + + RegistrarX + RegistrarX + 1999-04-03T22:00:00.0Z + 2015-04-03T22:00:00.0Z + + + + + example2.test + Dexample2-TEST + + + jd1234 + sh8013 + sh8013 + RegistrarX + RegistrarX + 1999-04-03T22:00:00.0Z + 2015-04-03T22:00:00.0Z + + + + + ns1.example.com + Hns1_example_com-TEST + + + 192.0.2.2 + 192.0.2.29 + 1080:0:0:0:8:800:200C:417A + + RegistrarX + RegistrarX + 1999-05-08T12:10:00.0Z + RegistrarX + 2009-10-03T09:34:00.0Z + + + + + ns1.example1.test + Hns1_example1_test-TEST + + + 192.0.2.2 + 192.0.2.29 + 1080:0:0:0:8:800:200C:417A + + RegistrarX + RegistrarX + 1999-05-08T12:10:00.0Z + RegistrarX + 2009-10-03T09:34:00.0Z + + + + + sh8013 + Csh8013-TEST + + + + John Doe + Example Inc. + + 123 Example Dr. + Suite 100 + Dulles + VA + 20166-6503 + US + + + +1.7035555555 + + +1.7035555556 + + jdoe@example.test + + RegistrarX + RegistrarX + + 2009-09-13T08:01:00.0Z + RegistrarX + + 2009-11-26T09:10:00.0Z + 2009-12-03T09:05:00.0Z + + + + + + + + + RegistrarY + Registrar Y + 123 + ok + + + 123 Example Dr. + + Suite 100 + + Dulles + VA + 20166-6503 + US + + + +1.7035555555 + + +1.7035555556 + + jdoe@example.test + + http://www.example.test + + + whois.example.test + + http://whois.example.test + + + 2005-04-23T11:49:00.0Z + 2009-02-17T17:51:00.0Z + + + + + +http://www.iana.org/domains/idn-tables/tables/br_pt-br_1.0.html + + + http://registro.br/dominio/regras.html + + + + + + xn--exampl-gva.test + pt-BR + example1.test + withheld + 2005-04-23T11:49:00.0Z + + + + + 1.0 + en + + urn:ietf:params:xml:ns:domain-1.0 + + + urn:ietf:params:xml:ns:contact-1.0 + + + urn:ietf:params:xml:ns:host-1.0 + + + urn:ietf:params:xml:ns:rgp-1.0 + + urn:ietf:params:xml:ns:secDNS-1.1 + + + + + + + + + + + + + + + + + + + + + + diff --git a/javatests/google/registry/rde/testdata/deposit_full_badtld.xml b/javatests/google/registry/rde/testdata/deposit_full_badtld.xml new file mode 100644 index 000000000..e2eab56ae --- /dev/null +++ b/javatests/google/registry/rde/testdata/deposit_full_badtld.xml @@ -0,0 +1,259 @@ + + + + 2010-10-17T00:00:00Z + + 1.0 + urn:ietf:params:xml:ns:rdeHeader-1.0 + urn:ietf:params:xml:ns:rdeContact-1.0 + urn:ietf:params:xml:ns:rdeHost-1.0 + urn:ietf:params:xml:ns:rdeDomain-1.0 + urn:ietf:params:xml:ns:rdeRegistrar-1.0 + urn:ietf:params:xml:ns:rdeIDN-1.0 + urn:ietf:params:xml:ns:rdeNNDN-1.0 + urn:ietf:params:xml:ns:rdeEppParams-1.0 + + + + + + + badtld + 2 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + + + + + example1.test + Dexample1-TEST + + jd1234 + sh8013 + sh8013 + + ns1.example.com + ns1.example1.test + + RegistrarX + RegistrarX + 1999-04-03T22:00:00.0Z + 2015-04-03T22:00:00.0Z + + + + + example2.test + Dexample2-TEST + + + jd1234 + sh8013 + sh8013 + RegistrarX + RegistrarX + 1999-04-03T22:00:00.0Z + 2015-04-03T22:00:00.0Z + + + + + ns1.example.com + Hns1_example_com-TEST + + + 192.0.2.2 + 192.0.2.29 + 1080:0:0:0:8:800:200C:417A + + RegistrarX + RegistrarX + 1999-05-08T12:10:00.0Z + RegistrarX + 2009-10-03T09:34:00.0Z + + + + + ns1.example1.test + Hns1_example1_test-TEST + + + 192.0.2.2 + 192.0.2.29 + 1080:0:0:0:8:800:200C:417A + + RegistrarX + RegistrarX + 1999-05-08T12:10:00.0Z + RegistrarX + 2009-10-03T09:34:00.0Z + + + + + sh8013 + Csh8013-TEST + + + + John Doe + Example Inc. + + 123 Example Dr. + Suite 100 + Dulles + VA + 20166-6503 + US + + + +1.7035555555 + + +1.7035555556 + + jdoe@example.test + + RegistrarX + RegistrarX + + 2009-09-13T08:01:00.0Z + RegistrarX + + 2009-11-26T09:10:00.0Z + 2009-12-03T09:05:00.0Z + + + + + + + + + RegistrarX + Registrar X + 123 + ok + + + 123 Example Dr. + + Suite 100 + + Dulles + VA + 20166-6503 + US + + + +1.7035555555 + + +1.7035555556 + + jdoe@example.test + + http://www.example.test + + + whois.example.test + + http://whois.example.test + + + 2005-04-23T11:49:00.0Z + 2009-02-17T17:51:00.0Z + + + + + +http://www.iana.org/domains/idn-tables/tables/br_pt-br_1.0.html + + + http://registro.br/dominio/regras.html + + + + + + xn--exampl-gva.test + pt-BR + example1.test + withheld + 2005-04-23T11:49:00.0Z + + + + + 1.0 + en + + urn:ietf:params:xml:ns:domain-1.0 + + + urn:ietf:params:xml:ns:contact-1.0 + + + urn:ietf:params:xml:ns:host-1.0 + + + urn:ietf:params:xml:ns:rgp-1.0 + + urn:ietf:params:xml:ns:secDNS-1.1 + + + + + + + + + + + + + + + + + + + + + + diff --git a/javatests/google/registry/rde/testdata/deposit_full_getld.xml b/javatests/google/registry/rde/testdata/deposit_full_getld.xml new file mode 100644 index 000000000..7f7f5138b --- /dev/null +++ b/javatests/google/registry/rde/testdata/deposit_full_getld.xml @@ -0,0 +1,259 @@ + + + + 2010-10-17T00:00:00Z + + 1.0 + urn:ietf:params:xml:ns:rdeHeader-1.0 + urn:ietf:params:xml:ns:rdeContact-1.0 + urn:ietf:params:xml:ns:rdeHost-1.0 + urn:ietf:params:xml:ns:rdeDomain-1.0 + urn:ietf:params:xml:ns:rdeRegistrar-1.0 + urn:ietf:params:xml:ns:rdeIDN-1.0 + urn:ietf:params:xml:ns:rdeNNDN-1.0 + urn:ietf:params:xml:ns:rdeEppParams-1.0 + + + + + + + getld + 2 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + + + + + example1.test + Dexample1-TEST + + jd1234 + sh8013 + sh8013 + + ns1.example.com + ns1.example1.test + + RegistrarX + RegistrarX + 1999-04-03T22:00:00.0Z + 2015-04-03T22:00:00.0Z + + + + + example2.test + Dexample2-TEST + + + jd1234 + sh8013 + sh8013 + RegistrarX + RegistrarX + 1999-04-03T22:00:00.0Z + 2015-04-03T22:00:00.0Z + + + + + ns1.example.com + Hns1_example_com-TEST + + + 192.0.2.2 + 192.0.2.29 + 1080:0:0:0:8:800:200C:417A + + RegistrarX + RegistrarX + 1999-05-08T12:10:00.0Z + RegistrarX + 2009-10-03T09:34:00.0Z + + + + + ns1.example1.test + Hns1_example1_test-TEST + + + 192.0.2.2 + 192.0.2.29 + 1080:0:0:0:8:800:200C:417A + + RegistrarX + RegistrarX + 1999-05-08T12:10:00.0Z + RegistrarX + 2009-10-03T09:34:00.0Z + + + + + sh8013 + Csh8013-TEST + + + + John Doe + Example Inc. + + 123 Example Dr. + Suite 100 + Dulles + VA + 20166-6503 + US + + + +1.7035555555 + + +1.7035555556 + + jdoe@example.test + + RegistrarX + RegistrarX + + 2009-09-13T08:01:00.0Z + RegistrarX + + 2009-11-26T09:10:00.0Z + 2009-12-03T09:05:00.0Z + + + + + + + + + RegistrarX + Registrar X + 123 + ok + + + 123 Example Dr. + + Suite 100 + + Dulles + VA + 20166-6503 + US + + + +1.7035555555 + + +1.7035555556 + + jdoe@example.test + + http://www.example.test + + + whois.example.test + + http://whois.example.test + + + 2005-04-23T11:49:00.0Z + 2009-02-17T17:51:00.0Z + + + + + +http://www.iana.org/domains/idn-tables/tables/br_pt-br_1.0.html + + + http://registro.br/dominio/regras.html + + + + + + xn--exampl-gva.test + pt-BR + example1.test + withheld + 2005-04-23T11:49:00.0Z + + + + + 1.0 + en + + urn:ietf:params:xml:ns:domain-1.0 + + + urn:ietf:params:xml:ns:contact-1.0 + + + urn:ietf:params:xml:ns:host-1.0 + + + urn:ietf:params:xml:ns:rgp-1.0 + + urn:ietf:params:xml:ns:secDNS-1.1 + + + + + + + + + + + + + + + + + + + + + + diff --git a/javatests/google/registry/testing/DatastoreHelper.java b/javatests/google/registry/testing/DatastoreHelper.java index 6b046c782..be50b90d9 100644 --- a/javatests/google/registry/testing/DatastoreHelper.java +++ b/javatests/google/registry/testing/DatastoreHelper.java @@ -573,6 +573,16 @@ public class DatastoreHelper { .build()); } + /** Creates a stripped-down {@link Registrar} with the specified clientId and ianaIdentifier */ + public static Registrar persistNewRegistrar(String clientId, long ianaIdentifier) { + return persistSimpleResource( + new Registrar.Builder() + .setClientIdentifier(clientId) + .setType(Registrar.Type.REAL) + .setIanaIdentifier(ianaIdentifier) + .build()); + } + private static Iterable getBillingEvents() { return Iterables.concat( ofy().load().type(BillingEvent.OneTime.class),