1
0
mirror of https://github.com/google/nomulus synced 2026-02-10 06:50:30 +00:00

Validate that a registrar has billing accounts for all its allowed TLDs (#1601)

This will require edits to a substantial number of registrars on sandbox (nearly
all of them) because almost all of them have access to at least one TLD, but
almost none of them have any billing accounts set. Until this is set, any updates
to the existing registrars that aren't adding the billing accounts will cause
failures.

Unfortunately, there wasn't any less invasive foolproof way to implement this
change, and we already had one attempt to implement it on create registrar
command that wasn't working (because allowed TLDs tend not to be added on
initial registrar creation, but rather, afterwards as an update).
This commit is contained in:
Ben McIlwain
2022-04-22 16:33:18 -04:00
committed by GitHub
parent 147d133aef
commit 1e76eeed37
15 changed files with 238 additions and 46 deletions

View File

@@ -336,7 +336,11 @@ public class SyncRegistrarsSheetTest {
@TestOfyAndSql
void testRun_missingValues_stillWorks() throws Exception {
persistNewRegistrar("SomeRegistrar", "Some Registrar", Registrar.Type.REAL, 8L);
persistResource(
persistNewRegistrar("SomeRegistrar", "Some Registrar", Registrar.Type.REAL, 8L)
.asBuilder()
.setBillingAccountMap(ImmutableMap.of())
.build());
newSyncRegistrarsSheet().run("foobar");

View File

@@ -30,11 +30,14 @@ import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DatabaseHelper.persistSimpleResource;
import static google.registry.testing.DatabaseHelper.persistSimpleResources;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.money.CurrencyUnit.USD;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig;
@@ -42,13 +45,17 @@ import google.registry.model.EntityTestCase;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.Registrar.Type;
import google.registry.model.tld.Registries;
import google.registry.model.tld.Registry;
import google.registry.model.tld.Registry.TldType;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestOfyOnly;
import google.registry.testing.TestSqlOnly;
import google.registry.util.CidrAddressBlock;
import google.registry.util.SerializeUtils;
import java.math.BigDecimal;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.junit.jupiter.api.BeforeEach;
/** Unit tests for {@link Registrar}. */
@@ -60,7 +67,20 @@ class RegistrarTest extends EntityTestCase {
@BeforeEach
void setUp() {
createTld("xn--q9jyb4c");
createTld("tld");
persistResource(
newRegistry("xn--q9jyb4c", "MINNA")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.of(JPY, new BigDecimal(1300)))
.setRestoreBillingCost(Money.of(JPY, new BigDecimal(1700)))
.setServerStatusChangeBillingCost(Money.of(JPY, new BigDecimal(1900)))
.setRegistryLockOrUnlockBillingCost(Money.of(JPY, new BigDecimal(2700)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.of(JPY, new BigDecimal(1100))))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(JPY)))
.setPremiumList(null)
.build());
// Set up a new persisted registrar entity.
registrar =
cloneAndSetAutoTimestamps(
@@ -251,8 +271,10 @@ class RegistrarTest extends EntityTestCase {
}
@TestOfyAndSql
void testSuccess_clearingBillingAccountMap() {
registrar = registrar.asBuilder().setBillingAccountMap(null).build();
void testSuccess_clearingBillingAccountMapAndAllowedTlds() {
registrar =
registrar.asBuilder().setAllowedTlds(ImmutableSet.of()).setBillingAccountMap(null).build();
assertThat(registrar.getAllowedTlds()).isEmpty();
assertThat(registrar.getBillingAccountMap()).isEmpty();
}
@@ -677,4 +699,48 @@ class RegistrarTest extends EntityTestCase {
assertThrows(IllegalArgumentException.class, () -> Registrar.loadByRegistrarIdCached(""));
assertThat(thrown).hasMessageThat().contains("registrarId must be specified");
}
@TestOfyAndSql
void testFailure_missingCurrenciesFromBillingMap() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
registrar
.asBuilder()
.setBillingAccountMap(null)
.setAllowedTlds(ImmutableSet.of("tld", "xn--q9jyb4c"))
.build());
assertThat(thrown)
.hasMessageThat()
.contains("their currency is missing from the billing account map: [tld, xn--q9jyb4c]");
}
@TestOfyAndSql
void testFailure_missingCurrencyFromBillingMap() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
registrar
.asBuilder()
.setBillingAccountMap(ImmutableMap.of(USD, "abc123"))
.setAllowedTlds(ImmutableSet.of("tld", "xn--q9jyb4c"))
.build());
assertThat(thrown)
.hasMessageThat()
.contains("their currency is missing from the billing account map: [xn--q9jyb4c]");
}
@TestOfyAndSql
void testSuccess_nonRealTldDoesntNeedEntryInBillingMap() {
persistResource(Registry.get("xn--q9jyb4c").asBuilder().setTldType(TldType.TEST).build());
// xn--q9jyb4c bills in JPY and we don't have a JPY entry in this billing account map, but it
// should succeed without throwing an error because xn--q9jyb4c is set to be a TEST TLD.
registrar
.asBuilder()
.setBillingAccountMap(ImmutableMap.of(USD, "abc123"))
.setAllowedTlds(ImmutableSet.of("tld", "xn--q9jyb4c"))
.build();
}
}

View File

@@ -190,7 +190,7 @@ public final class RegistryTest extends EntityTestCase {
@TestOfyAndSql
void testGetAll() {
createTld("foo");
assertThat(Registry.getAll(ImmutableSet.of("foo", "tld")))
assertThat(Registry.get(ImmutableSet.of("foo", "tld")))
.containsExactlyElementsIn(
tm().transact(
() ->

View File

@@ -66,6 +66,7 @@ import java.util.Set;
import java.util.logging.LogManager;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.joda.money.CurrencyUnit;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -289,6 +290,7 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa
.build())
.setPhoneNumber("+1.3334445555")
.setPhonePasscode("12345")
.setBillingAccountMap(ImmutableMap.of(CurrencyUnit.USD, "abc123"))
.setContactsRequireSyncing(true);
}

View File

@@ -762,6 +762,7 @@ public class DatabaseHelper {
.setType(type)
.setState(State.ACTIVE)
.setIanaIdentifier(ianaIdentifier)
.setBillingAccountMap(ImmutableMap.of(USD, "abc123"))
.setLocalizedAddress(
new RegistrarAddress.Builder()
.setStreet(ImmutableList.of("123 Fake St"))

View File

@@ -21,8 +21,11 @@ import static google.registry.testing.CertificateSamples.SAMPLE_CERT;
import static google.registry.testing.CertificateSamples.SAMPLE_CERT3;
import static google.registry.testing.CertificateSamples.SAMPLE_CERT3_HASH;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.newRegistry;
import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.JPY;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
@@ -43,8 +46,10 @@ import google.registry.testing.DualDatabaseTest;
import google.registry.testing.InjectExtension;
import google.registry.testing.TestOfyAndSql;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Optional;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -604,11 +609,11 @@ class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarCommand>
Optional<Registrar> registrar = Registrar.loadByRegistrarId("clientz");
assertThat(registrar).isPresent();
assertThat(registrar.get().getBillingAccountMap())
.containsExactly(CurrencyUnit.USD, "abc123", CurrencyUnit.JPY, "789xyz");
.containsExactly(CurrencyUnit.USD, "abc123", JPY, "789xyz");
}
@TestOfyAndSql
void testFailure_billingAccountMap_doesNotContainEntryForTldAllowed() {
void testFailure_billingAccountMap_doesNotContainEntryForAllowedTld() {
createTlds("foo");
IllegalArgumentException thrown =
@@ -632,12 +637,26 @@ class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarCommand>
"--cc US",
"--force",
"clientz"));
assertThat(thrown).hasMessageThat().contains("USD");
assertThat(thrown)
.hasMessageThat()
.contains("their currency is missing from the billing account map: [foo]");
}
@TestOfyAndSql
void testSuccess_billingAccountMap_onlyAppliesToRealRegistrar() throws Exception {
createTlds("foo");
persistResource(
newRegistry("foo", "FOO")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.of(JPY, new BigDecimal(1300)))
.setRestoreBillingCost(Money.of(JPY, new BigDecimal(1700)))
.setServerStatusChangeBillingCost(Money.of(JPY, new BigDecimal(1900)))
.setRegistryLockOrUnlockBillingCost(Money.of(JPY, new BigDecimal(2700)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.of(JPY, new BigDecimal(1100))))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(JPY)))
.setPremiumList(null)
.build());
runCommandForced(
"--name=blobio",
@@ -656,7 +675,7 @@ class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarCommand>
Optional<Registrar> registrar = Registrar.loadByRegistrarId("clientz");
assertThat(registrar).isPresent();
assertThat(registrar.get().getBillingAccountMap()).containsExactly(CurrencyUnit.JPY, "789xyz");
assertThat(registrar.get().getBillingAccountMap()).containsExactly(JPY, "789xyz");
}
@TestOfyAndSql

View File

@@ -21,8 +21,10 @@ import static google.registry.testing.CertificateSamples.SAMPLE_CERT3;
import static google.registry.testing.CertificateSamples.SAMPLE_CERT3_HASH;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.newRegistry;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.time.DateTimeZone.UTC;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -38,8 +40,10 @@ import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.Registrar.Type;
import google.registry.testing.AppEngineExtension;
import google.registry.util.CidrAddressBlock;
import java.math.BigDecimal;
import java.util.Optional;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -359,6 +363,8 @@ class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarCommand>
@Test
void testSuccess_billingAccountMap() throws Exception {
persistResource(
loadRegistrar("NewRegistrar").asBuilder().setBillingAccountMap(ImmutableMap.of()).build());
assertThat(loadRegistrar("NewRegistrar").getBillingAccountMap()).isEmpty();
runCommand("--billing_account_map=USD=abc123,JPY=789xyz", "--force", "NewRegistrar");
assertThat(loadRegistrar("NewRegistrar").getBillingAccountMap())
@@ -366,8 +372,14 @@ class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarCommand>
}
@Test
void testFailure_billingAccountMap_doesNotContainEntryForTldAllowed() {
void testFailure_billingAccountMap_doesNotContainEntryForAllowedTld() {
createTlds("foo");
persistResource(
loadRegistrar("NewRegistrar")
.asBuilder()
.setAllowedTlds(ImmutableSet.of())
.setBillingAccountMap(ImmutableMap.of())
.build());
assertThat(loadRegistrar("NewRegistrar").getBillingAccountMap()).isEmpty();
IllegalArgumentException thrown =
assertThrows(
@@ -379,12 +391,28 @@ class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarCommand>
"--force",
"--registrar_type=REAL",
"NewRegistrar"));
assertThat(thrown).hasMessageThat().contains("USD");
assertThat(thrown)
.hasMessageThat()
.contains("their currency is missing from the billing account map: [foo]");
}
@Test
void testSuccess_billingAccountMap_onlyAppliesToRealRegistrar() throws Exception {
createTlds("foo");
persistResource(
newRegistry("foo", "FOO")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.of(JPY, new BigDecimal(1300)))
.setRestoreBillingCost(Money.of(JPY, new BigDecimal(1700)))
.setServerStatusChangeBillingCost(Money.of(JPY, new BigDecimal(1900)))
.setRegistryLockOrUnlockBillingCost(Money.of(JPY, new BigDecimal(2700)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.of(JPY, new BigDecimal(1100))))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(JPY)))
.setPremiumList(null)
.build());
persistResource(
loadRegistrar("NewRegistrar").asBuilder().setBillingAccountMap(ImmutableMap.of()).build());
assertThat(loadRegistrar("NewRegistrar").getBillingAccountMap()).isEmpty();
runCommand("--billing_account_map=JPY=789xyz", "--allowed_tlds=foo", "--force", "NewRegistrar");
assertThat(loadRegistrar("NewRegistrar").getBillingAccountMap())