diff --git a/core/src/main/java/google/registry/bsa/IdnChecker.java b/core/src/main/java/google/registry/bsa/IdnChecker.java index d97a5345f..815538356 100644 --- a/core/src/main/java/google/registry/bsa/IdnChecker.java +++ b/core/src/main/java/google/registry/bsa/IdnChecker.java @@ -16,8 +16,8 @@ package google.registry.bsa; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.Maps.transformValues; +import static google.registry.model.tld.Tld.isEnrolledWithBsa; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; @@ -50,14 +50,6 @@ public class IdnChecker { allTlds = idnToTlds.values().stream().flatMap(ImmutableSet::stream).collect(toImmutableSet()); } - // TODO(11/30/2023): Remove below when new Tld schema is deployed and the `getBsaEnrollStartTime` - // method is no longer hardcoded. - @VisibleForTesting - IdnChecker(ImmutableMap> idnToTlds) { - this.idnToTlds = idnToTlds; - allTlds = idnToTlds.values().stream().flatMap(ImmutableSet::stream).collect(toImmutableSet()); - } - /** Returns all IDNs in which the {@code label} is valid. */ ImmutableSet getAllValidIdns(String label) { return idnToTlds.keySet().stream() @@ -88,11 +80,6 @@ public class IdnChecker { return Sets.difference(allTlds, getSupportingTlds(idnTables)); } - private static boolean isEnrolledWithBsa(Tld tld, DateTime now) { - DateTime enrollTime = tld.getBsaEnrollStartTime(); - return enrollTime != null && enrollTime.isBefore(now); - } - private static ImmutableMap> getIdnToTldMap(DateTime now) { ImmutableMultimap.Builder idnToTldMap = new ImmutableMultimap.Builder(); Tlds.getTldEntitiesOfType(TldType.REAL).stream() diff --git a/core/src/main/java/google/registry/model/tld/Tld.java b/core/src/main/java/google/registry/model/tld/Tld.java index 256a3ab74..3df2451fe 100644 --- a/core/src/main/java/google/registry/model/tld/Tld.java +++ b/core/src/main/java/google/registry/model/tld/Tld.java @@ -256,6 +256,11 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl return VKey.create(Tld.class, tldStr); } + /** Checks if {@code tld} is enrolled with BSA. */ + public static boolean isEnrolledWithBsa(Tld tld, DateTime now) { + return tld.getBsaEnrollStartTime().orElse(END_OF_TIME).isBefore(now); + } + /** * The name of the pricing engine that this TLD uses. * @@ -550,9 +555,15 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl @JsonSerialize(using = SortedEnumSetSerializer.class) Set idnTables; - // TODO(11/30/2023): uncomment below two lines - // /** The start time of this TLD's enrollment in the BSA program, if applicable. */ - // @JsonIgnore @Nullable DateTime bsaEnrollStartTime; + /** + * The start time of this TLD's enrollment in the BSA program, if applicable. + * + *

This property is excluded from source-based configuration and is managed directly in the + * database. + */ + // TODO(b/309175410): implement setup and cleanup procedure for joining or leaving BSA, and see + // if it can be integrated with the ConfigTldCommand. + @JsonIgnore @Nullable DateTime bsaEnrollStartTime; public String getTldStr() { return tldStr; @@ -574,12 +585,9 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl } /** Returns the time when this TLD was enrolled in the Brand Safety Alliance (BSA) program. */ - @JsonIgnore // Annotation can be removed once we add the field and annotate it. - @Nullable - public DateTime getBsaEnrollStartTime() { - // TODO(11/30/2023): uncomment below. - // return this.bsaEnrollStartTime; - return null; + @JsonIgnore + public Optional getBsaEnrollStartTime() { + return Optional.ofNullable(this.bsaEnrollStartTime); } /** Retrieve whether invoicing is enabled. */ @@ -1101,10 +1109,9 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl return this; } - public Builder setBsaEnrollStartTime(DateTime enrollTime) { + public Builder setBsaEnrollStartTime(Optional enrollTime) { // TODO(b/309175133): forbid if enrolled with BSA - // TODO(11/30/2023): uncomment below line - // getInstance().bsaEnrollStartTime = enrollTime; + getInstance().bsaEnrollStartTime = enrollTime.orElse(null); return this; } diff --git a/core/src/main/java/google/registry/tools/ConfigureTldCommand.java b/core/src/main/java/google/registry/tools/ConfigureTldCommand.java index b548743c0..f7302625f 100644 --- a/core/src/main/java/google/registry/tools/ConfigureTldCommand.java +++ b/core/src/main/java/google/registry/tools/ConfigureTldCommand.java @@ -122,6 +122,13 @@ public class ConfigureTldCommand extends MutatingCommand { checkPremiumList(newTld); checkDnsWriters(newTld); checkCurrency(newTld); + // bsaEnrollStartTime only exists in DB. Need to carry it over to the updated copy. See Tld.java + // for more information. + Optional bsaEnrollTime = + Optional.ofNullable(oldTld).flatMap(Tld::getBsaEnrollStartTime); + if (bsaEnrollTime.isPresent()) { + newTld = newTld.asBuilder().setBsaEnrollStartTime(bsaEnrollTime).build(); + } // Set the new TLD to breakglass mode if breakglass flag was used if (breakglass) { newTld = newTld.asBuilder().setBreakglassMode(true).build(); diff --git a/core/src/test/java/google/registry/bsa/IdnCheckerTest.java b/core/src/test/java/google/registry/bsa/IdnCheckerTest.java index 04b204fdc..6f0695c83 100644 --- a/core/src/test/java/google/registry/bsa/IdnCheckerTest.java +++ b/core/src/test/java/google/registry/bsa/IdnCheckerTest.java @@ -15,38 +15,65 @@ package google.registry.bsa; import static com.google.common.truth.Truth.assertThat; +import static google.registry.testing.DatabaseHelper.createTld; +import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.tldconfig.idn.IdnTableEnum.EXTENDED_LATIN; import static google.registry.tldconfig.idn.IdnTableEnum.JA; import static google.registry.tldconfig.idn.IdnTableEnum.UNCONFUSABLE_LATIN; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import google.registry.model.tld.Tld; +import google.registry.persistence.transaction.JpaTestExtensions; +import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationWithCoverageExtension; +import google.registry.testing.FakeClock; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; +import org.junit.jupiter.api.extension.RegisterExtension; -@ExtendWith(MockitoExtension.class) +/** Unit tests for {@link IdnChecker}. */ public class IdnCheckerTest { - @Mock Tld jaonly; - @Mock Tld jandelatin; - @Mock Tld strictlatin; + FakeClock fakeClock = new FakeClock(); + + @RegisterExtension + final JpaIntegrationWithCoverageExtension jpa = + new JpaTestExtensions.Builder().withClock(fakeClock).buildIntegrationWithCoverageExtension(); + + Tld jaonly; + Tld jandelatin; + Tld strictlatin; IdnChecker idnChecker; @BeforeEach void setup() { - idnChecker = - new IdnChecker( - ImmutableMap.of( - JA, - ImmutableSet.of(jandelatin, jaonly), - EXTENDED_LATIN, - ImmutableSet.of(jandelatin), - UNCONFUSABLE_LATIN, - ImmutableSet.of(strictlatin))); + jaonly = createTld("jaonly"); + jandelatin = createTld("jandelatin"); + strictlatin = createTld("strictlatin"); + + jaonly = + persistResource( + jaonly + .asBuilder() + .setBsaEnrollStartTime(Optional.of(fakeClock.nowUtc())) + .setIdnTables(ImmutableSet.of(JA)) + .build()); + jandelatin = + persistResource( + jandelatin + .asBuilder() + .setBsaEnrollStartTime(Optional.of(fakeClock.nowUtc())) + .setIdnTables(ImmutableSet.of(JA, EXTENDED_LATIN)) + .build()); + strictlatin = + persistResource( + strictlatin + .asBuilder() + .setBsaEnrollStartTime(Optional.of(fakeClock.nowUtc())) + .setIdnTables(ImmutableSet.of(UNCONFUSABLE_LATIN)) + .build()); + fakeClock.advanceOneMilli(); + idnChecker = new IdnChecker(fakeClock); } @Test diff --git a/core/src/test/java/google/registry/tools/ConfigureTldCommandTest.java b/core/src/test/java/google/registry/tools/ConfigureTldCommandTest.java index 7f3c371dc..cbac74db9 100644 --- a/core/src/test/java/google/registry/tools/ConfigureTldCommandTest.java +++ b/core/src/test/java/google/registry/tools/ConfigureTldCommandTest.java @@ -14,9 +14,9 @@ package google.registry.tools; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth8.assertThat; import static google.registry.model.EntityYamlUtils.createObjectMapper; import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO; -import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.testing.DatabaseHelper.createTld; import static google.registry.testing.DatabaseHelper.persistPremiumList; import static google.registry.testing.DatabaseHelper.persistResource; @@ -46,6 +46,7 @@ import google.registry.model.tld.Tld.TldNotFoundException; import google.registry.model.tld.label.PremiumList; import google.registry.model.tld.label.PremiumListDao; import java.io.File; +import java.util.Optional; import java.util.logging.Logger; import org.joda.money.Money; import org.joda.time.DateTime; @@ -101,20 +102,19 @@ public class ConfigureTldCommandTest extends CommandTestCase tm().put(tld.asBuilder().setBsaEnrollStartTime(bsaStartTime).build())); + persistResource(tld.asBuilder().setBsaEnrollStartTime(Optional.of(bsaStartTime)).build()); File tldFile = tmpDir.resolve("tld.yaml").toFile(); Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml")); runCommandForced("--input=" + tldFile); - // TODO(11/30/2023): uncomment below two lines - // Tld updatedTld = Tld.get("tld"); - // assertThat(tld.getBsaEnrollStartTime()).isEqualTo(bsaStartTime); + Tld updatedTld = Tld.get("tld"); + assertThat(updatedTld.getBsaEnrollStartTime()).hasValue(bsaStartTime); } @Test diff --git a/db/src/main/resources/sql/schema/db-schema.sql.generated b/db/src/main/resources/sql/schema/db-schema.sql.generated index 7c3c24ea8..8fdbba8d7 100644 --- a/db/src/main/resources/sql/schema/db-schema.sql.generated +++ b/db/src/main/resources/sql/schema/db-schema.sql.generated @@ -728,6 +728,7 @@ auto_renew_grace_period_length interval not null, automatic_transfer_length interval not null, breakglass_mode boolean not null, + bsa_enroll_start_time timestamptz, claims_period_end timestamptz not null, create_billing_cost_amount numeric(19, 2), create_billing_cost_currency text,