From 7f85d6a7de56bb880e4d3aa3312e863505c24e88 Mon Sep 17 00:00:00 2001 From: Ben McIlwain Date: Thu, 1 Oct 2026 18:42:01 +0000 Subject: [PATCH] Allow test TLDs in drop list export for non-production environments (#3231) In non-production environments (e.g. sandbox), allow TEST TLDs to be included in the domain drop list export so XAP can be verified with test TLDs. Also remove the isInvoicingEnabled filter globally, as the tld.getExpiryAccessPeriodModeAt(now) check is sufficient. TAG=agy CONV=67020217-639f-40a2-9d7c-54e592c91a53 --- .../registry/export/ExportDropListAction.java | 24 ++++--- .../java/google/registry/model/tld/Tlds.java | 5 ++ .../export/ExportDropListActionTest.java | 70 ++++++++++++++++--- .../google/registry/model/tld/TldsTest.java | 2 + 4 files changed, 85 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/google/registry/export/ExportDropListAction.java b/core/src/main/java/google/registry/export/ExportDropListAction.java index d33ffb535..a8e933753 100644 --- a/core/src/main/java/google/registry/export/ExportDropListAction.java +++ b/core/src/main/java/google/registry/export/ExportDropListAction.java @@ -16,6 +16,7 @@ package google.registry.export; import static com.google.common.base.Verify.verifyNotNull; import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static google.registry.model.tld.Tlds.getTldEntities; import static google.registry.model.tld.Tlds.getTldEntitiesOfType; import static google.registry.persistence.PersistenceModule.TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ; import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm; @@ -35,6 +36,7 @@ import google.registry.request.Action; import google.registry.request.auth.Auth; import google.registry.storage.drive.DriveConnection; import google.registry.util.Clock; +import google.registry.util.RegistryEnvironment; import jakarta.inject.Inject; import java.io.IOException; import java.io.StringWriter; @@ -45,7 +47,10 @@ import java.util.Optional; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; -/** An action that exports the upcoming domain drop list across all open TLDs to Google Drive. */ +/** + * An action that exports the upcoming domain drop list across TLDs with XAP enabled to Google + * Drive. + */ @Action( service = Action.Service.BACKEND, path = "/_dr/task/exportDropList", @@ -89,15 +94,18 @@ public class ExportDropListAction implements Runnable { Instant now = clock.now(); ImmutableSet xapTlds = - getTldEntitiesOfType(TldType.REAL).stream() - .filter(Tld::isInvoicingEnabled) - .filter(tld -> tld.getExpiryAccessPeriodModeAt(now) == ExpiryAccessPeriodMode.ENABLED) - .map(Tld::getTldStr) - .collect(toImmutableSet()); - logger.atInfo().log("Exporting domain drop list for open TLDs with XAP enabled: %s", xapTlds); + (RegistryEnvironment.get() == RegistryEnvironment.PRODUCTION + ? getTldEntitiesOfType(TldType.REAL) + : getTldEntities()) + .stream() + .filter( + tld -> tld.getExpiryAccessPeriodModeAt(now) == ExpiryAccessPeriodMode.ENABLED) + .map(Tld::getTldStr) + .collect(toImmutableSet()); + logger.atInfo().log("Exporting domain drop list for TLDs with XAP enabled: %s", xapTlds); if (xapTlds.isEmpty()) { - logger.atInfo().log("No open TLDs found with XAP enabled."); + logger.atInfo().log("No TLDs found with XAP enabled."); exportToDrive(createCsv(ImmutableList.of())); return; } diff --git a/core/src/main/java/google/registry/model/tld/Tlds.java b/core/src/main/java/google/registry/model/tld/Tlds.java index 33917608d..d7e7ff682 100644 --- a/core/src/main/java/google/registry/model/tld/Tlds.java +++ b/core/src/main/java/google/registry/model/tld/Tlds.java @@ -86,6 +86,11 @@ public final class Tlds { return ImmutableSet.copyOf(filterValues(cache.get(), equalTo(type)).keySet()); } + /** Returns all TLD entities loaded fresh from the database. */ + public static ImmutableSet getTldEntities() { + return Tld.get(cache.get().keySet()); + } + /** Returns the TLD entities themselves of the given type loaded fresh from the database. */ public static ImmutableSet getTldEntitiesOfType(TldType type) { return Tld.get(filterValues(cache.get(), equalTo(type)).keySet()); diff --git a/core/src/test/java/google/registry/export/ExportDropListActionTest.java b/core/src/test/java/google/registry/export/ExportDropListActionTest.java index 8612e5cfe..d412a03da 100644 --- a/core/src/test/java/google/registry/export/ExportDropListActionTest.java +++ b/core/src/test/java/google/registry/export/ExportDropListActionTest.java @@ -39,10 +39,13 @@ import google.registry.persistence.transaction.JpaTestExtensions; import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension; import google.registry.storage.drive.DriveConnection; import google.registry.testing.FakeClock; +import google.registry.testing.SystemPropertyExtension; +import google.registry.util.RegistryEnvironment; import java.io.IOException; import java.time.Instant; import java.util.Optional; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.ArgumentCaptor; @@ -59,6 +62,10 @@ class ExportDropListActionTest { final JpaIntegrationTestExtension jpa = new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension(); + @RegisterExtension + @Order(Integer.MAX_VALUE) + final SystemPropertyExtension systemPropertyExtension = new SystemPropertyExtension(); + @BeforeEach void beforeEach() { createTld("open1"); @@ -80,11 +87,23 @@ class ExportDropListActionTest { .build()); createTld("closed"); - persistResource(Tld.get("closed").asBuilder().setInvoicingEnabled(false).build()); + persistResource( + Tld.get("closed") + .asBuilder() + .setInvoicingEnabled(false) + .setExpiryAccessPeriodTransitions( + ImmutableSortedMap.of(START_INSTANT, ExpiryAccessPeriodMode.ENABLED)) + .build()); createTld("testtld"); persistResource( - Tld.get("testtld").asBuilder().setTldType(TldType.TEST).setInvoicingEnabled(true).build()); + Tld.get("testtld") + .asBuilder() + .setTldType(TldType.TEST) + .setInvoicingEnabled(false) + .setExpiryAccessPeriodTransitions( + ImmutableSortedMap.of(START_INSTANT, ExpiryAccessPeriodMode.ENABLED)) + .build()); action = new ExportDropListAction(); action.clock = clock; @@ -104,7 +123,7 @@ class ExportDropListActionTest { } @Test - void test_exportsDropListAcrossOpenTlds_sortedByDomainName() throws Exception { + void test_exportsDropListAcrossTlds_sortedByDomainName() throws Exception { // Active domain with no drop date (END_INSTANT) on open TLD -> excluded persistActiveDomain("active.open1"); @@ -112,9 +131,12 @@ class ExportDropListActionTest { persistDeletedDomain("zebra.open1", Instant.parse("2020-02-07T02:02:02Z")); persistDeletedDomain("alpha.open2", Instant.parse("2020-02-04T02:02:02Z")); - // Pending delete domain on non-invoicing (closed) TLD -> excluded + // Pending delete domain on non-invoicing (closed) TLD with XAP enabled -> included persistDeletedDomain("closed.closed", Instant.parse("2020-02-05T02:02:02Z")); + // Pending delete domain on test TLD with XAP enabled in non-PROD -> included + persistDeletedDomain("test.testtld", Instant.parse("2020-02-06T02:02:02Z")); + // Pending delete domain on open TLD with XAP disabled -> excluded createTld("noxap"); persistResource( @@ -126,9 +148,6 @@ class ExportDropListActionTest { .build()); persistDeletedDomain("noxap.noxap", Instant.parse("2020-02-05T02:02:02Z")); - // Pending delete domain on test TLD -> excluded - persistDeletedDomain("test.testtld", Instant.parse("2020-02-06T02:02:02Z")); - // Already deleted domain on open TLD -> excluded persistDeletedDomain("deleted.open1", Instant.parse("2020-02-01T02:02:02Z")); @@ -138,10 +157,33 @@ class ExportDropListActionTest { """ domain_name,tld,deletion_time alpha.open2,open2,2020-02-04T02:02:02Z + closed.closed,closed,2020-02-05T02:02:02Z + test.testtld,testtld,2020-02-06T02:02:02Z zebra.open1,open1,2020-02-07T02:02:02Z """); } + @Test + void test_exportsDropList_excludesTestTldsInProduction() throws Exception { + RegistryEnvironment.PRODUCTION.setup(systemPropertyExtension); + + // Pending delete domains on open TLD and non-invoicing TLD with XAP enabled -> included + persistDeletedDomain("alpha.open2", Instant.parse("2020-02-04T02:02:02Z")); + persistDeletedDomain("closed.closed", Instant.parse("2020-02-05T02:02:02Z")); + + // Pending delete domain on test TLD with XAP enabled -> excluded in PROD + persistDeletedDomain("test.testtld", Instant.parse("2020-02-06T02:02:02Z")); + + action.run(); + + verifyExportedToDrive( + """ + domain_name,tld,deletion_time + alpha.open2,open2,2020-02-04T02:02:02Z + closed.closed,closed,2020-02-05T02:02:02Z + """); + } + @Test void test_skipsDriveExport_whenDriveFolderIdIsEmpty() { action.driveFolderId = Optional.empty(); @@ -164,7 +206,7 @@ class ExportDropListActionTest { } @Test - void test_noOpenTldsWithXap_outputsHeaderOnly() throws Exception { + void test_noTldsWithXap_outputsHeaderOnly() throws Exception { persistResource( Tld.get("open1") .asBuilder() @@ -177,6 +219,18 @@ class ExportDropListActionTest { .setExpiryAccessPeriodTransitions( ImmutableSortedMap.of(START_INSTANT, ExpiryAccessPeriodMode.DISABLED)) .build()); + persistResource( + Tld.get("closed") + .asBuilder() + .setExpiryAccessPeriodTransitions( + ImmutableSortedMap.of(START_INSTANT, ExpiryAccessPeriodMode.DISABLED)) + .build()); + persistResource( + Tld.get("testtld") + .asBuilder() + .setExpiryAccessPeriodTransitions( + ImmutableSortedMap.of(START_INSTANT, ExpiryAccessPeriodMode.DISABLED)) + .build()); persistDeletedDomain("zebra.open1", Instant.parse("2020-02-07T02:02:02Z")); diff --git a/core/src/test/java/google/registry/model/tld/TldsTest.java b/core/src/test/java/google/registry/model/tld/TldsTest.java index f939e8aa0..f75ca9b9b 100644 --- a/core/src/test/java/google/registry/model/tld/TldsTest.java +++ b/core/src/test/java/google/registry/model/tld/TldsTest.java @@ -54,6 +54,8 @@ class TldsTest { void test_getTldEntities() { initTestTlds(); persistResource(newTld("testtld", "TESTTLD").asBuilder().setTldType(TldType.TEST).build()); + assertThat(Tlds.getTldEntities()) + .containsExactly(Tld.get("foo"), Tld.get("a.b.c"), Tld.get("testtld")); assertThat(Tlds.getTldEntitiesOfType(TldType.REAL)) .containsExactly(Tld.get("foo"), Tld.get("a.b.c")); assertThat(Tlds.getTldEntitiesOfType(TldType.TEST)).containsExactly(Tld.get("testtld"));