diff --git a/common/src/main/java/google/registry/util/Clock.java b/common/src/main/java/google/registry/util/Clock.java index 78372cba4bc..9943aaa7cec 100644 --- a/common/src/main/java/google/registry/util/Clock.java +++ b/common/src/main/java/google/registry/util/Clock.java @@ -15,6 +15,7 @@ package google.registry.util; import java.io.Serializable; +import java.time.Instant; import javax.annotation.concurrent.ThreadSafe; import org.joda.time.DateTime; @@ -30,5 +31,9 @@ public interface Clock extends Serializable { /** Returns current time in UTC timezone. */ + @Deprecated DateTime nowUtc(); + + /** Returns current Instant (which is always in UTC). */ + Instant now(); } diff --git a/common/src/main/java/google/registry/util/DateTimeUtils.java b/common/src/main/java/google/registry/util/DateTimeUtils.java index b085fbabdc8..025ca3dde81 100644 --- a/common/src/main/java/google/registry/util/DateTimeUtils.java +++ b/common/src/main/java/google/registry/util/DateTimeUtils.java @@ -20,6 +20,9 @@ import com.google.common.collect.Lists; import com.google.common.collect.Ordering; import java.sql.Date; +import java.time.Instant; +import java.time.ZoneOffset; +import javax.annotation.Nullable; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; @@ -28,7 +31,10 @@ public abstract class DateTimeUtils { /** The start of the epoch, in a convenient constant. */ - public static final DateTime START_OF_TIME = new DateTime(0, DateTimeZone.UTC); + @Deprecated public static final DateTime START_OF_TIME = new DateTime(0, DateTimeZone.UTC); + + /** The start of the UNIX epoch in UTC, in a convenient constant. */ + public static final Instant START_INSTANT = Instant.ofEpochMilli(0); /** * A date in the far future that we can treat as infinity. @@ -37,19 +43,40 @@ public abstract class DateTimeUtils { * but Java uses milliseconds, so this is the largest representable date that will survive a * round-trip through the database. */ + @Deprecated public static final DateTime END_OF_TIME = new DateTime(Long.MAX_VALUE / 1000, DateTimeZone.UTC); + /** + * An instant in the far future that we can treat as infinity. + * + *

This value is (2^63-1)/1000 rounded down. Postgres can store dates as 64 bit microseconds, + * but Java uses milliseconds, so this is the largest representable date that will survive a + * round-trip through the database. + */ + public static final Instant END_INSTANT = Instant.ofEpochMilli(Long.MAX_VALUE / 1000); + /** Returns the earliest of a number of given {@link DateTime} instances. */ public static DateTime earliestOf(DateTime first, DateTime... rest) { + return earliestDateTimeOf(Lists.asList(first, rest)); + } + + /** Returns the earliest of a number of given {@link Instant} instances. */ + public static Instant earliestOf(Instant first, Instant... rest) { return earliestOf(Lists.asList(first, rest)); } /** Returns the earliest element in a {@link DateTime} iterable. */ - public static DateTime earliestOf(Iterable dates) { + public static DateTime earliestDateTimeOf(Iterable dates) { checkArgument(!Iterables.isEmpty(dates)); return Ordering.natural().min(dates); } + /** Returns the earliest element in a {@link Instant} iterable. */ + public static Instant earliestOf(Iterable instants) { + checkArgument(!Iterables.isEmpty(instants)); + return Ordering.natural().min(instants); + } + /** Returns the latest of a number of given {@link DateTime} instances. */ public static DateTime latestOf(DateTime first, DateTime... rest) { return latestOf(Lists.asList(first, rest)); @@ -66,29 +93,63 @@ public static boolean isBeforeOrAt(DateTime timeToCheck, DateTime timeToCompareT return !timeToCheck.isAfter(timeToCompareTo); } + /** Returns whether the first {@link Instant} is equal to or earlier than the second. */ + public static boolean isBeforeOrAt(Instant timeToCheck, Instant timeToCompareTo) { + return !timeToCheck.isAfter(timeToCompareTo); + } + /** Returns whether the first {@link DateTime} is equal to or later than the second. */ public static boolean isAtOrAfter(DateTime timeToCheck, DateTime timeToCompareTo) { return !timeToCheck.isBefore(timeToCompareTo); } + /** Returns whether the first {@link Instant} is equal to or later than the second. */ + public static boolean isAtOrAfter(Instant timeToCheck, Instant timeToCompareTo) { + return !timeToCheck.isBefore(timeToCompareTo); + } + /** * Adds years to a date, in the {@code Duration} sense of semantic years. Use this instead of * {@link DateTime#plusYears} to ensure that we never end up on February 29. */ + @Deprecated public static DateTime leapSafeAddYears(DateTime now, int years) { checkArgument(years >= 0); return years == 0 ? now : now.plusYears(1).plusYears(years - 1); } + /** + * Adds years to a date, in the {@code Duration} sense of semantic years. Use this instead of + * {@link DateTime#plusYears} to ensure that we never end up on February 29. + */ + public static Instant leapSafeAddYears(Instant now, long years) { + checkArgument(years >= 0); + return (years == 0) + ? now + : now.atZone(ZoneOffset.UTC).plusYears(1).plusYears(years - 1).toInstant(); + } + /** * Subtracts years from a date, in the {@code Duration} sense of semantic years. Use this instead * of {@link DateTime#minusYears} to ensure that we never end up on February 29. */ + @Deprecated public static DateTime leapSafeSubtractYears(DateTime now, int years) { checkArgument(years >= 0); return years == 0 ? now : now.minusYears(1).minusYears(years - 1); } + /** + * Subtracts years from a date, in the {@code Duration} sense of semantic years. Use this instead + * of {@link DateTime#minusYears} to ensure that we never end up on February 29. + */ + public static Instant leapSafeSubtractYears(Instant now, long years) { + checkArgument(years >= 0); + return (years == 0) + ? now + : now.atZone(ZoneOffset.UTC).minusYears(1).minusYears(years - 1).toInstant(); + } + public static Date toSqlDate(LocalDate localDate) { return new Date(localDate.toDateTimeAtStartOfDay().getMillis()); } @@ -96,4 +157,28 @@ public static Date toSqlDate(LocalDate localDate) { public static LocalDate toLocalDate(Date date) { return new LocalDate(date.getTime(), DateTimeZone.UTC); } + + /** Convert a joda {@link DateTime} to a java.time {@link Instant}, null-safe. */ + @Nullable + public static Instant toInstant(@Nullable DateTime dateTime) { + return (dateTime == null) ? null : Instant.ofEpochMilli(dateTime.getMillis()); + } + + /** Convert a java.time {@link Instant} to a joda {@link DateTime}, null-safe. */ + @Nullable + public static DateTime toDateTime(@Nullable Instant instant) { + return (instant == null) ? null : new DateTime(instant.toEpochMilli(), DateTimeZone.UTC); + } + + public static Instant plusYears(Instant instant, int years) { + return instant.atZone(ZoneOffset.UTC).plusYears(years).toInstant(); + } + + public static Instant plusDays(Instant instant, int days) { + return instant.atZone(ZoneOffset.UTC).plusDays(days).toInstant(); + } + + public static Instant minusDays(Instant instant, int days) { + return instant.atZone(ZoneOffset.UTC).minusDays(days).toInstant(); + } } diff --git a/common/src/main/java/google/registry/util/SystemClock.java b/common/src/main/java/google/registry/util/SystemClock.java index eb553678d45..7e4e7551c1c 100644 --- a/common/src/main/java/google/registry/util/SystemClock.java +++ b/common/src/main/java/google/registry/util/SystemClock.java @@ -17,6 +17,7 @@ import static org.joda.time.DateTimeZone.UTC; import jakarta.inject.Inject; +import java.time.Instant; import javax.annotation.concurrent.ThreadSafe; import org.joda.time.DateTime; @@ -34,4 +35,13 @@ public SystemClock() {} public DateTime nowUtc() { return DateTime.now(UTC); } + + @Override + public Instant now() { + // Truncate to milliseconds to match the precision of Joda DateTime and our database schema + // (which uses millisecond precision via DateTimeConverter). This prevents subtle comparison + // bugs where a high-precision Instant would be considered "after" a truncated database + // timestamp. + return Instant.now().truncatedTo(java.time.temporal.ChronoUnit.MILLIS); + } } diff --git a/common/src/testing/java/google/registry/testing/FakeClock.java b/common/src/testing/java/google/registry/testing/FakeClock.java index 526f943a2ea..656ec7109b9 100644 --- a/common/src/testing/java/google/registry/testing/FakeClock.java +++ b/common/src/testing/java/google/registry/testing/FakeClock.java @@ -19,6 +19,7 @@ import static org.joda.time.Duration.millis; import google.registry.util.Clock; +import java.time.Instant; import java.util.concurrent.atomic.AtomicLong; import javax.annotation.concurrent.ThreadSafe; import org.joda.time.DateTime; @@ -54,6 +55,11 @@ public DateTime nowUtc() { return new DateTime(currentTimeMillis.addAndGet(autoIncrementStepMs), UTC); } + @Override + public Instant now() { + return Instant.ofEpochMilli(currentTimeMillis.addAndGet(autoIncrementStepMs)); + } + /** * Sets the increment applied to the clock whenever it is queried. The increment is zero by * default: the clock is left unchanged when queried. diff --git a/core/src/main/java/google/registry/batch/BulkDomainTransferAction.java b/core/src/main/java/google/registry/batch/BulkDomainTransferAction.java index 990428edde9..b3bcc419d3b 100644 --- a/core/src/main/java/google/registry/batch/BulkDomainTransferAction.java +++ b/core/src/main/java/google/registry/batch/BulkDomainTransferAction.java @@ -17,6 +17,7 @@ import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8; import static google.registry.flows.FlowUtils.marshalWithLenientRetry; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.util.DateTimeUtils.END_INSTANT; import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; import static jakarta.servlet.http.HttpServletResponse.SC_NO_CONTENT; import static jakarta.servlet.http.HttpServletResponse.SC_OK; @@ -39,7 +40,6 @@ import google.registry.request.Response; import google.registry.request.auth.Auth; import google.registry.request.lock.LockHandler; -import google.registry.util.DateTimeUtils; import jakarta.inject.Inject; import jakarta.inject.Named; import java.util.Optional; @@ -212,7 +212,7 @@ private void runTransferFlowInTransaction(String domainName) { private boolean shouldSkipDomain(String domainName) { Optional maybeDomain = - ForeignKeyUtils.loadResource(Domain.class, domainName, tm().getTransactionTime()); + ForeignKeyUtils.loadResource(Domain.class, domainName, tm().getTxTime()); if (maybeDomain.isEmpty()) { logger.atWarning().log("Domain '%s' was already deleted", domainName); missingDomains++; @@ -232,7 +232,7 @@ private boolean shouldSkipDomain(String domainName) { return true; } if (domain.getStatusValues().contains(StatusValue.PENDING_DELETE) - || !domain.getDeletionTime().equals(DateTimeUtils.END_OF_TIME)) { + || !domain.getDeletionTime().equals(END_INSTANT)) { logger.atWarning().log("Domain '%s' is in PENDING_DELETE", domainName); pendingDelete++; return true; diff --git a/core/src/main/java/google/registry/batch/DeleteExpiredDomainsAction.java b/core/src/main/java/google/registry/batch/DeleteExpiredDomainsAction.java index 5281360342c..a23d5ce17eb 100644 --- a/core/src/main/java/google/registry/batch/DeleteExpiredDomainsAction.java +++ b/core/src/main/java/google/registry/batch/DeleteExpiredDomainsAction.java @@ -18,6 +18,7 @@ import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8; import static google.registry.flows.FlowUtils.marshalWithLenientRetry; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.util.DateTimeUtils.END_INSTANT; import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.ResourceUtils.readResourceUtf8; import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; @@ -177,7 +178,7 @@ private boolean runDomainDeleteFlow(Domain domain) { "Failed to delete domain %s because of its autorenew end time: %s.", transDomain.getDomainName(), transDomain.getAutorenewEndTime()); return Optional.empty(); - } else if (domain.getDeletionTime().isBefore(END_OF_TIME)) { + } else if (domain.getDeletionTime().isBefore(END_INSTANT)) { logger.atSevere().log( "Failed to delete domain %s because it was already deleted on %s.", transDomain.getDomainName(), transDomain.getDeletionTime()); diff --git a/core/src/main/java/google/registry/batch/DeleteProberDataAction.java b/core/src/main/java/google/registry/batch/DeleteProberDataAction.java index c34718b4875..f442f308a42 100644 --- a/core/src/main/java/google/registry/batch/DeleteProberDataAction.java +++ b/core/src/main/java/google/registry/batch/DeleteProberDataAction.java @@ -28,7 +28,6 @@ import static google.registry.request.RequestParameters.PARAM_DRY_RUN; import static google.registry.request.RequestParameters.PARAM_TLDS; import static google.registry.util.RegistryEnvironment.PRODUCTION; -import static org.joda.time.DateTimeZone.UTC; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; @@ -44,6 +43,7 @@ import google.registry.request.Action; import google.registry.request.Parameter; import google.registry.request.auth.Auth; +import google.registry.util.Clock; import google.registry.util.RegistryEnvironment; import jakarta.inject.Inject; import jakarta.persistence.TypedQuery; @@ -111,16 +111,20 @@ public class DeleteProberDataAction implements Runnable { String registryAdminRegistrarId; + private final Clock clock; + @Inject DeleteProberDataAction( @Parameter(PARAM_DRY_RUN) boolean isDryRun, @Parameter(PARAM_TLDS) ImmutableSet tlds, @Parameter(PARAM_BATCH_SIZE) Optional batchSize, - @Config("registryAdminClientId") String registryAdminRegistrarId) { + @Config("registryAdminClientId") String registryAdminRegistrarId, + Clock clock) { this.isDryRun = isDryRun; this.tlds = tlds; this.batchSize = batchSize.orElse(DEFAULT_BATCH_SIZE); this.registryAdminRegistrarId = registryAdminRegistrarId; + this.clock = clock; } @Override @@ -145,7 +149,7 @@ public void run() { AtomicInteger softDeletedDomains = new AtomicInteger(); AtomicInteger hardDeletedDomains = new AtomicInteger(); AtomicReference> domainsBatch = new AtomicReference<>(); - DateTime startTime = DateTime.now(UTC); + DateTime startTime = clock.nowUtc(); do { tm().transact( TRANSACTION_REPEATABLE_READ, @@ -164,7 +168,7 @@ public void run() { hardDeletedDomains.get(), batchSize); // Automatically kill the job if it is running for over 20 hours - } while (DateTime.now(UTC).isBefore(startTime.plusHours(20)) + } while (clock.nowUtc().isBefore(startTime.plusHours(20)) && domainsBatch.get().size() == batchSize); logger.atInfo().log( "%s %d domains.", diff --git a/core/src/main/java/google/registry/batch/RelockDomainAction.java b/core/src/main/java/google/registry/batch/RelockDomainAction.java index f9a5ab5bec9..010eef40f93 100644 --- a/core/src/main/java/google/registry/batch/RelockDomainAction.java +++ b/core/src/main/java/google/registry/batch/RelockDomainAction.java @@ -188,7 +188,7 @@ private void verifyDomainAndLockState(RegistryLock oldLock, Domain domain) { "Domain %s has a pending delete.", domainName); checkArgument( - !DateTimeUtils.isAtOrAfter(tm().getTransactionTime(), domain.getDeletionTime()), + !DateTimeUtils.isAtOrAfter(tm().getTxTime(), domain.getDeletionTime()), "Domain %s has been deleted.", domainName); checkArgument( diff --git a/core/src/main/java/google/registry/batch/SendExpiringCertificateNotificationEmailAction.java b/core/src/main/java/google/registry/batch/SendExpiringCertificateNotificationEmailAction.java index 4ee917951ad..02cd0dc6fb8 100644 --- a/core/src/main/java/google/registry/batch/SendExpiringCertificateNotificationEmailAction.java +++ b/core/src/main/java/google/registry/batch/SendExpiringCertificateNotificationEmailAction.java @@ -19,7 +19,6 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; import static org.apache.http.HttpStatus.SC_OK; -import static org.joda.time.DateTimeZone.UTC; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; @@ -37,6 +36,7 @@ import google.registry.request.Action; import google.registry.request.Response; import google.registry.request.auth.Auth; +import google.registry.util.Clock; import google.registry.util.EmailMessage; import jakarta.inject.Inject; import jakarta.mail.internet.AddressException; @@ -73,6 +73,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable private final GmailClient gmailClient; private final String expirationWarningEmailSubjectText; private final Response response; + private final Clock clock; @Inject public SendExpiringCertificateNotificationEmailAction( @@ -80,12 +81,14 @@ public SendExpiringCertificateNotificationEmailAction( @Config("expirationWarningEmailSubjectText") String expirationWarningEmailSubjectText, GmailClient gmailClient, CertificateChecker certificateChecker, - Response response) { + Response response, + Clock clock) { this.certificateChecker = certificateChecker; this.expirationWarningEmailSubjectText = expirationWarningEmailSubjectText; this.gmailClient = gmailClient; this.expirationWarningEmailBodyText = expirationWarningEmailBodyText; this.response = response; + this.clock = clock; } @Override @@ -186,7 +189,7 @@ boolean sendNotificationEmail( */ updateLastNotificationSentDate( registrar, - DateTime.now(UTC).minusMinutes((int) UPDATE_TIME_OFFSET.getStandardMinutes()), + clock.nowUtc().minusMinutes((int) UPDATE_TIME_OFFSET.getStandardMinutes()), certificateType); return true; } catch (Exception e) { diff --git a/core/src/main/java/google/registry/beam/billing/ExpandBillingRecurrencesPipeline.java b/core/src/main/java/google/registry/beam/billing/ExpandBillingRecurrencesPipeline.java index 193103c69a9..1bfcc1c487c 100644 --- a/core/src/main/java/google/registry/beam/billing/ExpandBillingRecurrencesPipeline.java +++ b/core/src/main/java/google/registry/beam/billing/ExpandBillingRecurrencesPipeline.java @@ -24,6 +24,7 @@ import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.earliestOf; import static google.registry.util.DateTimeUtils.latestOf; +import static google.registry.util.DateTimeUtils.toInstant; import static org.apache.beam.sdk.values.TypeDescriptors.voids; import com.google.common.collect.ImmutableMap; @@ -372,7 +373,7 @@ private void expandOneRecurrence( // during ARGP). // // See: DomainFlowUtils#createCancellingRecords - domain.getDeletionTime().isBefore(billingTime) + domain.getDeletionTime().isBefore(toInstant(billingTime)) ? ImmutableSet.of() : ImmutableSet.of( DomainTransactionRecord.create( diff --git a/core/src/main/java/google/registry/bigquery/BigqueryConnection.java b/core/src/main/java/google/registry/bigquery/BigqueryConnection.java index 93bf6fae9d2..d001645f8a3 100644 --- a/core/src/main/java/google/registry/bigquery/BigqueryConnection.java +++ b/core/src/main/java/google/registry/bigquery/BigqueryConnection.java @@ -24,7 +24,6 @@ import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static google.registry.bigquery.BigqueryUtils.toJobReferenceString; import static google.registry.config.RegistryConfig.getProjectId; -import static org.joda.time.DateTimeZone.UTC; import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.client.http.AbstractInputStreamContent; @@ -58,6 +57,7 @@ import google.registry.bigquery.BigqueryUtils.DestinationFormat; import google.registry.bigquery.BigqueryUtils.TableType; import google.registry.bigquery.BigqueryUtils.WriteDisposition; +import google.registry.util.Clock; import google.registry.util.NonFinalForTesting; import google.registry.util.Sleeper; import google.registry.util.SqlTemplate; @@ -69,7 +69,6 @@ import java.util.Random; import java.util.concurrent.ExecutorService; import javax.annotation.Nullable; -import org.joda.time.DateTime; import org.joda.time.Duration; /** Class encapsulating parameters and state for accessing the Bigquery API. */ @@ -94,6 +93,9 @@ public class BigqueryConnection implements AutoCloseable { /** Bigquery client instance wrapped by this class. */ private final Bigquery bigquery; + /** Clock instance for this connection. */ + private final Clock clock; + /** Executor service for bigquery jobs. */ private ListeningExecutorService service; @@ -109,8 +111,9 @@ public class BigqueryConnection implements AutoCloseable { /** Duration to wait between polls for job status. */ private Duration pollInterval = Duration.millis(1000); - BigqueryConnection(Bigquery bigquery) { + BigqueryConnection(Bigquery bigquery, Clock clock) { this.bigquery = bigquery; + this.clock = clock; } /** Builder for a {@link BigqueryConnection}, since the latter is immutable once created. */ @@ -118,8 +121,8 @@ public static class Builder { private BigqueryConnection instance; @Inject - Builder(Bigquery bigquery) { - instance = new BigqueryConnection(bigquery); + Builder(Bigquery bigquery, Clock clock) { + instance = new BigqueryConnection(bigquery, clock); } /** @@ -195,6 +198,11 @@ public static final class Builder { private final TableReference tableRef = new TableReference(); private TableType type = TableType.TABLE; private WriteDisposition writeDisposition = WriteDisposition.WRITE_EMPTY; + private final Clock clock; + + public Builder(Clock clock) { + this.clock = clock; + } public Builder datasetId(String datasetId) { tableRef.setDatasetId(datasetId); @@ -217,7 +225,7 @@ public Builder type(TableType type) { } public Builder timeToLive(Duration duration) { - this.table.setExpirationTime(DateTime.now(UTC).plus(duration).getMillis()); + this.table.setExpirationTime(clock.nowUtc().plus(duration).getMillis()); return this; } @@ -302,7 +310,7 @@ public void close() { /** Returns a partially built DestinationTable with the default dataset and overwrite behavior. */ public DestinationTable.Builder buildDestinationTable(String tableName) { - return new DestinationTable.Builder() + return new DestinationTable.Builder(clock) .datasetId(datasetId) .type(TableType.TABLE) .name(tableName) @@ -314,7 +322,7 @@ public DestinationTable.Builder buildDestinationTable(String tableName) { * temporary table dataset, with the default TTL and overwrite behavior. */ public DestinationTable.Builder buildTemporaryTable() { - return new DestinationTable.Builder() + return new DestinationTable.Builder(clock) .datasetId(TEMP_DATASET_NAME) .type(TableType.TABLE) .name(getRandomTableName()) diff --git a/core/src/main/java/google/registry/flows/ResourceFlowUtils.java b/core/src/main/java/google/registry/flows/ResourceFlowUtils.java index 122d5ded3b0..101bafa96f0 100644 --- a/core/src/main/java/google/registry/flows/ResourceFlowUtils.java +++ b/core/src/main/java/google/registry/flows/ResourceFlowUtils.java @@ -16,6 +16,7 @@ import static com.google.common.collect.Sets.intersection; import static google.registry.model.EppResourceUtils.isLinked; +import static google.registry.util.DateTimeUtils.toInstant; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; @@ -44,6 +45,7 @@ import google.registry.model.host.Host; import google.registry.model.transfer.TransferStatus; import google.registry.persistence.VKey; +import java.time.Instant; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -89,6 +91,11 @@ public static void verifyTransferInitiator(String registrarId, Domain domain) public static R loadAndVerifyExistence( Class clazz, String targetId, DateTime now) throws ResourceDoesNotExistException { + return loadAndVerifyExistence(clazz, targetId, toInstant(now)); + } + + public static R loadAndVerifyExistence( + Class clazz, String targetId, Instant now) throws ResourceDoesNotExistException { return verifyExistence(clazz, targetId, ForeignKeyUtils.loadResource(clazz, targetId, now)); } @@ -197,8 +204,8 @@ public static void verifyAllStatusesAreClientSettable(Set statusVal * * @param domain is the domain already projected at approvalTime */ - public static DateTime computeExDateForApprovalTime( - DomainBase domain, DateTime approvalTime, Period period) { + public static Instant computeExDateForApprovalTime( + DomainBase domain, Instant approvalTime, Period period) { boolean inAutoRenew = domain.getGracePeriodStatuses().contains(GracePeriodStatus.AUTO_RENEW); // inAutoRenew is set to false if the period is zero because a zero-period transfer should not // subsume an autorenew. diff --git a/core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java b/core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java index 6414aa93b80..9cb5a7c4b66 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java @@ -236,7 +236,7 @@ public EppResponse run() throws EppException { } // Cancel any grace periods that were still active, and set the expiration time accordingly. - DateTime newExpirationTime = existingDomain.getRegistrationExpirationTime(); + DateTime newExpirationTime = existingDomain.getRegistrationExpirationDateTime(); for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) { // No cancellation is written if the grace period was not for a billable event. if (gracePeriod.hasBillingEvent()) { @@ -289,7 +289,7 @@ public EppResponse run() throws EppException { flowCustomLogic.beforeResponse( BeforeResponseParameters.newBuilder() .setResultCode( - newDomain.getDeletionTime().isAfter(now) + newDomain.getDeletionDateTime().isAfter(now) ? SUCCESS_WITH_ACTION_PENDING : SUCCESS) .setResponseExtensions( diff --git a/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java b/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java index fb6b358dca1..3a2fdd196fc 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java +++ b/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java @@ -503,7 +503,7 @@ public static BillingRecurrence.Builder newAutorenewBillingEvent(Domain domain) .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setTargetId(domain.getDomainName()) .setRegistrarId(domain.getCurrentSponsorRegistrarId()) - .setEventTime(domain.getRegistrationExpirationTime()); + .setEventTime(domain.getRegistrationExpirationDateTime()); } /** @@ -514,7 +514,7 @@ public static Autorenew.Builder newAutorenewPollMessage(Domain domain) { return new Autorenew.Builder() .setTargetId(domain.getDomainName()) .setRegistrarId(domain.getCurrentSponsorRegistrarId()) - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setMsg("Domain was auto-renewed."); } @@ -658,7 +658,7 @@ static void handleFeeRequest( // process, don't count as expired for the purposes of requiring an added year of renewal on // restore because they can't be restored in the first place. boolean isExpired = - domain.isPresent() && domain.get().getRegistrationExpirationTime().isBefore(now); + domain.isPresent() && domain.get().getRegistrationExpirationDateTime().isBefore(now); fees = pricingLogic.getRestorePrice(tld, domainNameString, now, isExpired).getFees(); } case TRANSFER -> { diff --git a/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java b/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java index 15a9b1b48c9..8815d2ca7bd 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java @@ -122,8 +122,8 @@ public EppResponse run() throws EppException { .setNameservers( hostsRequest.requestDelegated() ? domain.loadNameserverHostNames() : null) .setCreationTime(domain.getCreationTime()) - .setLastEppUpdateTime(domain.getLastEppUpdateTime()) - .setRegistrationExpirationTime(domain.getRegistrationExpirationTime()) + .setLastEppUpdateTime(domain.getLastEppUpdateDateTime()) + .setRegistrationExpirationTime(domain.getRegistrationExpirationDateTime()) .setLastTransferTime(domain.getLastTransferTime()); // If authInfo is non-null, then the caller is authorized to see the full information since we diff --git a/core/src/main/java/google/registry/flows/domain/DomainRenewFlow.java b/core/src/main/java/google/registry/flows/domain/DomainRenewFlow.java index ec7d982ca77..32278bf53d4 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainRenewFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainRenewFlow.java @@ -191,7 +191,7 @@ public EppResponse run() throws EppException { existingDomain = maybeApplyBulkPricingRemovalToken(existingDomain, allocationToken); DateTime newExpirationTime = - leapSafeAddYears(existingDomain.getRegistrationExpirationTime(), years); // Uncapped + leapSafeAddYears(existingDomain.getRegistrationExpirationDateTime(), years); // Uncapped validateRegistrationPeriod(now, newExpirationTime); Optional feeRenew = eppInput.getSingleExtension(FeeRenewCommandExtension.class); @@ -328,8 +328,9 @@ private void verifyRenewAllowed( // We only allow __REMOVE_BULK_PRICING__ token on bulk pricing domains for now verifyBulkTokenAllowedOnDomain(existingDomain, allocationToken); // If the date they specify doesn't match the expiration, fail. (This is an idempotence check). - if (!command.getCurrentExpirationDate().equals( - existingDomain.getRegistrationExpirationTime().toLocalDate())) { + if (!command + .getCurrentExpirationDate() + .equals(existingDomain.getRegistrationExpirationDateTime().toLocalDate())) { throw new IncorrectCurrentExpirationDateException(); } } diff --git a/core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java b/core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java index 29fc413d351..3ec154e7f8b 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java @@ -138,7 +138,7 @@ public EppResponse run() throws EppException { Update command = (Update) resourceCommand; DateTime now = tm().getTransactionTime(); Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now); - boolean isExpired = existingDomain.getRegistrationExpirationTime().isBefore(now); + boolean isExpired = existingDomain.getRegistrationExpirationDateTime().isBefore(now); FeesAndCredits feesAndCredits = pricingLogic.getRestorePrice(Tld.get(existingDomain.getTld()), targetId, now, isExpired); Optional feeUpdate = @@ -149,7 +149,7 @@ public EppResponse run() throws EppException { ImmutableSet.Builder entitiesToInsert = new ImmutableSet.Builder<>(); DateTime newExpirationTime = - existingDomain.getRegistrationExpirationTime().plusYears(isExpired ? 1 : 0); + existingDomain.getRegistrationExpirationDateTime().plusYears(isExpired ? 1 : 0); // Restore the expiration time on the deleted domain, except if that's already passed, then add // a year and bill for it immediately, with no grace period. if (isExpired) { diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java index cea6f656825..7b7eb47b328 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java @@ -33,6 +33,8 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.util.CollectionUtils.union; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.toDateTime; +import static google.registry.util.DateTimeUtils.toInstant; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -193,7 +195,9 @@ public EppResponse run() throws EppException { updateAutorenewRecurrenceEndTime( existingDomain, existingBillingRecurrence, now, domainHistoryId); DateTime newExpirationTime = - computeExDateForApprovalTime(existingDomain, now, transferData.getTransferPeriod()); + toDateTime( + computeExDateForApprovalTime( + existingDomain, toInstant(now), transferData.getTransferPeriod())); // Create a new autorenew event starting at the expiration time. BillingRecurrence autorenewEvent = new BillingRecurrence.Builder() @@ -268,8 +272,11 @@ public EppResponse run() throws EppException { // been implicitly server approved. tm().delete(existingDomain.getTransferData().getServerApproveEntities()); return responseBuilder - .setResData(createTransferResponse( - targetId, newDomain.getTransferData(), newDomain.getRegistrationExpirationTime())) + .setResData( + createTransferResponse( + targetId, + newDomain.getTransferData(), + newDomain.getRegistrationExpirationDateTime())) .build(); } diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java index b562422b6b5..3e002f60c13 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java @@ -15,15 +15,17 @@ package google.registry.flows.domain; import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn; +import static google.registry.flows.ResourceFlowUtils.computeExDateForApprovalTime; import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse; +import static google.registry.util.DateTimeUtils.toDateTime; +import static google.registry.util.DateTimeUtils.toInstant; import google.registry.flows.EppException; import google.registry.flows.ExtensionManager; import google.registry.flows.FlowModule.RegistrarId; import google.registry.flows.FlowModule.TargetId; -import google.registry.flows.ResourceFlowUtils; import google.registry.flows.TransactionalFlow; import google.registry.flows.annotations.ReportingSpec; import google.registry.flows.exceptions.NoTransferHistoryToQueryException; @@ -88,11 +90,12 @@ public EppResponse run() throws EppException { } DateTime newExpirationTime = null; if (transferData.getTransferStatus().isApproved()) { - newExpirationTime = transferData.getTransferredRegistrationExpirationTime(); + newExpirationTime = transferData.getTransferredRegistrationExpirationDateTime(); } else if (transferData.getTransferStatus().equals(TransferStatus.PENDING)) { newExpirationTime = - ResourceFlowUtils.computeExDateForApprovalTime( - domain, now, domain.getTransferData().getTransferPeriod()); + toDateTime( + computeExDateForApprovalTime( + domain, toInstant(now), domain.getTransferData().getTransferPeriod())); } return responseBuilder .setResData(createTransferResponse(targetId, transferData, newExpirationTime)) diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferRejectFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferRejectFlow.java index 351ee5e18fd..39b25d8d551 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferRejectFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferRejectFlow.java @@ -32,6 +32,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.util.CollectionUtils.union; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.toDateTime; import com.google.common.collect.ImmutableSet; import google.registry.flows.EppException; @@ -53,6 +54,7 @@ import google.registry.model.tld.Tld; import google.registry.model.transfer.TransferStatus; import jakarta.inject.Inject; +import java.time.Instant; import java.util.Optional; import org.joda.time.DateTime; @@ -92,7 +94,7 @@ public EppResponse run() throws EppException { extensionManager.register(MetadataExtension.class); validateRegistrarIsLoggedIn(registrarId); extensionManager.validate(); - DateTime now = tm().getTransactionTime(); + Instant now = tm().getTxTime(); Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now); Tld tld = Tld.get(existingDomain.getTld()); HistoryEntryId domainHistoryId = createHistoryEntryId(existingDomain); @@ -107,13 +109,14 @@ public EppResponse run() throws EppException { checkAllowedAccessToTld(registrarId, existingDomain.getTld()); } Domain newDomain = - denyPendingTransfer(existingDomain, TransferStatus.CLIENT_REJECTED, now, registrarId); - DomainHistory domainHistory = buildDomainHistory(newDomain, tld, now); + denyPendingTransfer( + existingDomain, TransferStatus.CLIENT_REJECTED, toDateTime(now), registrarId); + DomainHistory domainHistory = buildDomainHistory(newDomain, tld, toDateTime(now)); tm().update(newDomain); tm().insertAll( domainHistory, createGainingTransferPollMessage( - targetId, newDomain.getTransferData(), null, now, domainHistoryId)); + targetId, newDomain.getTransferData(), null, toDateTime(now), domainHistoryId)); // Reopen the autorenew event and poll message that we closed for the implicit transfer. This // may end up recreating the poll message if it was deleted upon the transfer request. BillingRecurrence existingBillingRecurrence = diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java index db7ce17bfe5..ad711a9b722 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java @@ -35,6 +35,8 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING; import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.util.DateTimeUtils.toDateTime; +import static google.registry.util.DateTimeUtils.toInstant; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -80,6 +82,7 @@ import google.registry.model.transfer.TransferResponse.DomainTransferResponse; import google.registry.model.transfer.TransferStatus; import jakarta.inject.Inject; +import java.time.Instant; import java.util.Optional; import org.joda.time.DateTime; @@ -230,7 +233,9 @@ public EppResponse run() throws EppException { Domain domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime); // The new expiration time if there is a server approval. DateTime serverApproveNewExpirationTime = - computeExDateForApprovalTime(domainAtTransferTime, automaticTransferTime, period); + toDateTime( + computeExDateForApprovalTime( + domainAtTransferTime, toInstant(automaticTransferTime), period)); // Create speculative entities in anticipation of an automatic server approval. ImmutableSet serverApproveEntities = createTransferServerApproveEntities( @@ -287,7 +292,7 @@ public EppResponse run() throws EppException { tm().insertAll(domainHistory, requestPollMessage); return responseBuilder .setResultFromCode(SUCCESS_WITH_ACTION_PENDING) - .setResData(createResponse(period, existingDomain, newDomain, now)) + .setResData(createResponse(period, existingDomain, newDomain, toInstant(now))) .setExtensions(createResponseExtensions(feesAndCredits, feeTransfer)) .build(); } @@ -375,14 +380,14 @@ private DomainHistory buildDomainHistory(Domain newDomain, Tld tld, DateTime now } private DomainTransferResponse createResponse( - Period period, Domain existingDomain, Domain newDomain, DateTime now) { + Period period, Domain existingDomain, Domain newDomain, Instant now) { // If the registration were approved this instant, this is what the new expiration would be, // because we cap at 10 years from the moment of approval. This is different from the server // approval new expiration time, which is capped at 10 years from the server approve time. - DateTime approveNowExtendedRegistrationTime = + Instant approveNowExtendedRegistrationTime = computeExDateForApprovalTime(existingDomain, now, period); return createTransferResponse( - targetId, newDomain.getTransferData(), approveNowExtendedRegistrationTime); + targetId, newDomain.getTransferData(), toDateTime(approveNowExtendedRegistrationTime)); } private static ImmutableList createResponseExtensions( diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferUtils.java b/core/src/main/java/google/registry/flows/domain/DomainTransferUtils.java index 60000b224d5..f9c0ab16372 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferUtils.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferUtils.java @@ -184,7 +184,7 @@ public static PollMessage createGainingTransferPollMessage( HistoryEntryId domainHistoryId) { return new PollMessage.OneTime.Builder() .setRegistrarId(transferData.getGainingRegistrarId()) - .setEventTime(transferData.getPendingTransferExpirationTime()) + .setEventTime(transferData.getPendingTransferExpirationDateTime()) .setMsg(transferData.getTransferStatus().getMessage()) .setResponseData( ImmutableList.of( @@ -206,7 +206,7 @@ public static PollMessage createLosingTransferPollMessage( HistoryEntryId domainHistoryId) { return new PollMessage.OneTime.Builder() .setRegistrarId(transferData.getLosingRegistrarId()) - .setEventTime(transferData.getPendingTransferExpirationTime()) + .setEventTime(transferData.getPendingTransferExpirationDateTime()) .setMsg(transferData.getTransferStatus().getMessage()) .setResponseData( ImmutableList.of( @@ -224,7 +224,7 @@ static DomainTransferResponse createTransferResponse( .setDomainName(targetId) .setGainingRegistrarId(transferData.getGainingRegistrarId()) .setLosingRegistrarId(transferData.getLosingRegistrarId()) - .setPendingTransferExpirationTime(transferData.getPendingTransferExpirationTime()) + .setPendingTransferExpirationTime(transferData.getPendingTransferExpirationDateTime()) .setTransferRequestTime(transferData.getTransferRequestTime()) .setTransferStatus(transferData.getTransferStatus()) .setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime) diff --git a/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java b/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java index 16f89e57b82..752c194ebbf 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java @@ -281,7 +281,7 @@ private Domain performUpdate(Update command, Domain domain, DateTime now) throws if (superuserExt.get().getAutorenews().isPresent()) { boolean autorenews = superuserExt.get().getAutorenews().get(); domainBuilder.setAutorenewEndTime( - Optional.ofNullable(autorenews ? null : domain.getRegistrationExpirationTime())); + Optional.ofNullable(autorenews ? null : domain.getRegistrationExpirationDateTime())); } } return domainBuilder.build(); diff --git a/core/src/main/java/google/registry/flows/host/HostInfoFlow.java b/core/src/main/java/google/registry/flows/host/HostInfoFlow.java index af5a5b25851..4647ade8963 100644 --- a/core/src/main/java/google/registry/flows/host/HostInfoFlow.java +++ b/core/src/main/java/google/registry/flows/host/HostInfoFlow.java @@ -99,7 +99,7 @@ public EppResponse run() throws EppException { .setCreationRegistrarId(host.getCreationRegistrarId()) .setCreationTime(host.getCreationTime()) .setLastEppUpdateRegistrarId(host.getLastEppUpdateRegistrarId()) - .setLastEppUpdateTime(host.getLastEppUpdateTime()) + .setLastEppUpdateTime(host.getLastEppUpdateDateTime()) .build()) .build(); } diff --git a/core/src/main/java/google/registry/model/EppResource.java b/core/src/main/java/google/registry/model/EppResource.java index ee5c376ef63..f8007038f2d 100644 --- a/core/src/main/java/google/registry/model/EppResource.java +++ b/core/src/main/java/google/registry/model/EppResource.java @@ -25,6 +25,7 @@ import static google.registry.util.CollectionUtils.nullToEmpty; import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.toInstant; import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.LoadingCache; @@ -45,6 +46,7 @@ import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Transient; import java.time.Duration; +import java.time.Instant; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -163,10 +165,15 @@ public String getCreationRegistrarId() { return creationRegistrarId; } - public DateTime getLastEppUpdateTime() { + @Deprecated + public DateTime getLastEppUpdateDateTime() { return lastEppUpdateTime; } + public Instant getLastEppUpdateTime() { + return toInstant(lastEppUpdateTime); + } + public String getLastEppUpdateRegistrarId() { return lastEppUpdateRegistrarId; } @@ -185,13 +192,22 @@ public final ImmutableSet getStatusValues() { return nullToEmptyImmutableCopy(statuses); } - public DateTime getDeletionTime() { + @Deprecated + public DateTime getDeletionDateTime() { return deletionTime; } + public Instant getDeletionTime() { + return toInstant(deletionTime); + } + /** Return a clone of the resource with timed status values modified using the given time. */ + @Deprecated public abstract EppResource cloneProjectedAtTime(DateTime now); + /** Return a clone of the resource with timed status values modified using the given time. */ + public abstract EppResource cloneProjectedAtInstant(Instant now); + /** Get the foreign key string for this resource. */ public abstract String getForeignKey(); diff --git a/core/src/main/java/google/registry/model/EppResourceUtils.java b/core/src/main/java/google/registry/model/EppResourceUtils.java index 4af8c6ccf5c..c64591ce426 100644 --- a/core/src/main/java/google/registry/model/EppResourceUtils.java +++ b/core/src/main/java/google/registry/model/EppResourceUtils.java @@ -34,6 +34,7 @@ import google.registry.model.transfer.TransferStatus; import google.registry.persistence.VKey; import jakarta.persistence.Query; +import java.time.Instant; import java.util.Comparator; import java.util.function.Function; import javax.annotation.Nullable; @@ -83,7 +84,7 @@ public static Function transformAtTime(final DateT * exclusive, which happily maps to the behavior of Interval. */ private static Interval getLifetime(EppResource resource) { - return new Interval(resource.getCreationTime(), resource.getDeletionTime()); + return new Interval(resource.getCreationTime(), resource.getDeletionDateTime()); } public static boolean isActive(EppResource resource, DateTime time) { @@ -108,7 +109,7 @@ public static void setAutomaticTransferSuccessProperties( builder .removeStatusValue(StatusValue.PENDING_TRANSFER) .setTransferData(transferDataBuilder.build()) - .setLastTransferTime(transferData.getPendingTransferExpirationTime()) + .setLastTransferTime(transferData.getPendingTransferExpirationDateTime()) .setPersistedCurrentSponsorRegistrarId(transferData.getGainingRegistrarId()); } @@ -120,10 +121,10 @@ public static void setAutomaticTransferSuccessProperties( * */ public static void projectResourceOntoBuilderAtTime( - DomainBase domain, DomainBase.Builder builder, DateTime now) { + DomainBase domain, DomainBase.Builder builder, Instant now) { DomainTransferData transferData = domain.getTransferData(); // If there's a pending transfer that has expired, process it. - DateTime expirationTime = transferData.getPendingTransferExpirationTime(); + Instant expirationTime = transferData.getPendingTransferExpirationTime(); if (TransferStatus.PENDING.equals(transferData.getTransferStatus()) && isBeforeOrAt(expirationTime, now)) { setAutomaticTransferSuccessProperties(builder, transferData); diff --git a/core/src/main/java/google/registry/model/ForeignKeyUtils.java b/core/src/main/java/google/registry/model/ForeignKeyUtils.java index 9a0b08006e0..ba1ab670b79 100644 --- a/core/src/main/java/google/registry/model/ForeignKeyUtils.java +++ b/core/src/main/java/google/registry/model/ForeignKeyUtils.java @@ -35,6 +35,7 @@ import google.registry.persistence.transaction.JpaTransactionManager; import google.registry.util.NonFinalForTesting; import java.time.Duration; +import java.time.Instant; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; @@ -81,6 +82,7 @@ public static Optional> loadKey( *

Returns null if no resource with this foreign key was ever created or if the most recently * created resource was deleted before time "now". */ + @Deprecated public static Optional loadResource( Class clazz, String foreignKey, DateTime now) { // Note: no need to project to "now" because loadResources already does @@ -88,6 +90,19 @@ public static Optional loadResource( loadResources(clazz, ImmutableList.of(foreignKey), now).get(foreignKey)); } + /** + * Loads an {@link EppResource} from the database by foreign key. + * + *

Returns null if no resource with this foreign key was ever created or if the most recently + * created resource was deleted before time "now". + */ + public static Optional loadResource( + Class clazz, String foreignKey, Instant now) { + // Note: no need to project to "now" because loadResources already does + return Optional.ofNullable( + loadResources(clazz, ImmutableList.of(foreignKey), now).get(foreignKey)); + } + /** * Load a map of {@link String} foreign keys to {@link VKey}s to {@link EppResource} that are * active at or after the specified moment in time. @@ -110,13 +125,29 @@ public static ImmutableMap> loadKeys( * or has been soft-deleted. */ @SuppressWarnings("unchecked") + @Deprecated public static ImmutableMap loadResources( Class clazz, Collection foreignKeys, DateTime now) { return loadMostRecentResourceObjects(clazz, foreignKeys, false).entrySet().stream() - .filter(e -> now.isBefore(e.getValue().getDeletionTime())) + .filter(e -> now.isBefore(e.getValue().getDeletionDateTime())) .collect(toImmutableMap(Entry::getKey, e -> (E) e.getValue().cloneProjectedAtTime(now))); } + /** + * Load a map of {@link String} foreign keys to the {@link EppResource} that are active at or + * after the specified moment in time. + * + *

The returned map will omit any foreign keys for which the {@link EppResource} doesn't exist + * or has been soft-deleted. + */ + @SuppressWarnings("unchecked") + public static ImmutableMap loadResources( + Class clazz, Collection foreignKeys, Instant now) { + return loadMostRecentResourceObjects(clazz, foreignKeys, false).entrySet().stream() + .filter(e -> now.isBefore(e.getValue().getDeletionTime())) + .collect(toImmutableMap(Entry::getKey, e -> (E) e.getValue().cloneProjectedAtInstant(now))); + } + /** * Helper method to load {@link VKey}s to all the most recent {@link EppResource}s for the given * foreign keys, regardless of whether they have been soft-deleted. @@ -397,7 +428,7 @@ public static Optional loadResourceByCache( return (Optional) foreignKeyToResourceCache .get(VKey.create(clazz, foreignKey)) - .filter(e -> now.isBefore(e.getDeletionTime())) + .filter(e -> now.isBefore(e.getDeletionDateTime())) .map(e -> e.cloneProjectedAtTime(now)); } } diff --git a/core/src/main/java/google/registry/model/ResourceTransferUtils.java b/core/src/main/java/google/registry/model/ResourceTransferUtils.java index c6a70026622..7d4bc12c628 100644 --- a/core/src/main/java/google/registry/model/ResourceTransferUtils.java +++ b/core/src/main/java/google/registry/model/ResourceTransferUtils.java @@ -50,11 +50,11 @@ public static TransferResponse createTransferResponse( .setDomainName(domain.getForeignKey()) .setExtendedRegistrationExpirationTime( ADD_EXDATE_STATUSES.contains(transferData.getTransferStatus()) - ? transferData.getTransferredRegistrationExpirationTime() + ? transferData.getTransferredRegistrationExpirationDateTime() : null) .setGainingRegistrarId(transferData.getGainingRegistrarId()) .setLosingRegistrarId(transferData.getLosingRegistrarId()) - .setPendingTransferExpirationTime(transferData.getPendingTransferExpirationTime()) + .setPendingTransferExpirationTime(transferData.getPendingTransferExpirationDateTime()) .setTransferRequestTime(transferData.getTransferRequestTime()) .setTransferStatus(transferData.getTransferStatus()) .build(); diff --git a/core/src/main/java/google/registry/model/billing/BillingCancellation.java b/core/src/main/java/google/registry/model/billing/BillingCancellation.java index 1adc3a8f163..045e87b956a 100644 --- a/core/src/main/java/google/registry/model/billing/BillingCancellation.java +++ b/core/src/main/java/google/registry/model/billing/BillingCancellation.java @@ -104,7 +104,7 @@ public static google.registry.model.billing.BillingCancellation forGracePeriod( .setRegistrarId(gracePeriod.getRegistrarId()) .setEventTime(eventTime) // The charge being cancelled will take place at the grace period's expiration time. - .setBillingTime(gracePeriod.getExpirationTime()) + .setBillingTime(gracePeriod.getExpirationDateTime()) .setDomainHistoryId(domainHistoryId); // Set the grace period's billing event using the appropriate Cancellation builder method. if (gracePeriod.getBillingEvent() != null) { diff --git a/core/src/main/java/google/registry/model/domain/Domain.java b/core/src/main/java/google/registry/model/domain/Domain.java index 9a9715243a7..cff00f4db31 100644 --- a/core/src/main/java/google/registry/model/domain/Domain.java +++ b/core/src/main/java/google/registry/model/domain/Domain.java @@ -14,6 +14,8 @@ package google.registry.model.domain; +import static google.registry.util.DateTimeUtils.toInstant; + import google.registry.model.EppResource; import google.registry.model.EppResource.ForeignKeyedEppResource; import google.registry.model.annotations.ExternalMessagingName; @@ -37,6 +39,7 @@ import jakarta.persistence.JoinTable; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import java.time.Instant; import java.util.Set; import org.hibernate.Hibernate; import org.joda.time.DateTime; @@ -153,6 +156,11 @@ public VKey createVKey() { @Override public Domain cloneProjectedAtTime(final DateTime now) { + return cloneDomainProjectedAtTime(this, toInstant(now)); + } + + @Override + public Domain cloneProjectedAtInstant(final Instant now) { return cloneDomainProjectedAtTime(this, now); } diff --git a/core/src/main/java/google/registry/model/domain/DomainBase.java b/core/src/main/java/google/registry/model/domain/DomainBase.java index 573f5d213ce..1f051b567ee 100644 --- a/core/src/main/java/google/registry/model/domain/DomainBase.java +++ b/core/src/main/java/google/registry/model/domain/DomainBase.java @@ -32,9 +32,14 @@ import static google.registry.util.DateTimeUtils.earliestOf; import static google.registry.util.DateTimeUtils.isBeforeOrAt; import static google.registry.util.DateTimeUtils.leapSafeAddYears; +import static google.registry.util.DateTimeUtils.plusYears; +import static google.registry.util.DateTimeUtils.toDateTime; +import static google.registry.util.DateTimeUtils.toInstant; import static google.registry.util.DomainNameUtils.canonicalizeHostname; import static google.registry.util.DomainNameUtils.getTldFromDomainName; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; +import static java.time.ZoneOffset.UTC; +import static java.time.temporal.ChronoUnit.YEARS; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; @@ -79,13 +84,13 @@ import jakarta.persistence.Id; import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Transient; +import java.time.Instant; import java.util.HashSet; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; import org.hibernate.collection.spi.PersistentSet; import org.joda.time.DateTime; -import org.joda.time.Interval; /** * A persistable domain resource including mutable and non-mutable fields. @@ -285,10 +290,15 @@ public ImmutableSet getSubordinateHosts() { return nullToEmptyImmutableCopy(subordinateHosts); } - public DateTime getRegistrationExpirationTime() { + @Deprecated + public DateTime getRegistrationExpirationDateTime() { return registrationExpirationTime; } + public Instant getRegistrationExpirationTime() { + return toInstant(registrationExpirationTime); + } + public VKey getDeletePollMessage() { return deletePollMessage; } @@ -436,6 +446,11 @@ public ImmutableSet getGracePeriodsOfType(GracePeriodStatus gracePe @Override public DomainBase cloneProjectedAtTime(final DateTime now) { + return cloneDomainProjectedAtTime(this, toInstant(now)); + } + + @Override + public DomainBase cloneProjectedAtInstant(final Instant now) { return cloneDomainProjectedAtTime(this, now); } @@ -444,9 +459,9 @@ public DomainBase cloneProjectedAtTime(final DateTime now) { * parallels the logic in {@code DomainTransferApproveFlow} which handles explicit client * approvals. */ - static T cloneDomainProjectedAtTime(T domain, DateTime now) { + static T cloneDomainProjectedAtTime(T domain, Instant now) { DomainTransferData transferData = domain.getTransferData(); - DateTime transferExpirationTime = transferData.getPendingTransferExpirationTime(); + Instant transferExpirationTime = transferData.getPendingTransferExpirationTime(); // If there's a pending transfer that has expired, handle it. if (TransferStatus.PENDING.equals(transferData.getTransferStatus()) @@ -459,7 +474,7 @@ && isBeforeOrAt(transferExpirationTime, now)) { T domainAtTransferTime = cloneDomainProjectedAtTime(domain, transferExpirationTime.minusMillis(1)); - DateTime expirationDate = transferData.getTransferredRegistrationExpirationTime(); + Instant expirationDate = transferData.getTransferredRegistrationExpirationTime(); if (expirationDate == null) { // Extend the registration by the correct number of years from the expiration time // that was current on the domain right before the transfer, capped at 10 years from @@ -478,7 +493,7 @@ && isBeforeOrAt(transferExpirationTime, now)) { Builder builder = domainAtTransferTime .asBuilder() - .setRegistrationExpirationTime(expirationDate) + .setRegistrationExpirationTime(toDateTime(expirationDate)) // Set the speculatively-written new autorenew events as the domain's autorenew // events. .setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent()) @@ -492,8 +507,8 @@ && isBeforeOrAt(transferExpirationTime, now)) { GracePeriod.create( GracePeriodStatus.TRANSFER, domain.getRepoId(), - transferExpirationTime.plus( - Tld.get(domain.getTld()).getTransferGracePeriodLength()), + toDateTime(transferExpirationTime) + .plus(Tld.get(domain.getTld()).getTransferGracePeriodLength()), transferData.getGainingRegistrarId(), transferData.getServerApproveBillingEvent()))); } else { @@ -503,32 +518,33 @@ && isBeforeOrAt(transferExpirationTime, now)) { // Set all remaining transfer properties. setAutomaticTransferSuccessProperties(builder, transferData); builder - .setLastEppUpdateTime(transferExpirationTime) + .setLastEppUpdateTime(toDateTime(transferExpirationTime)) .setLastEppUpdateRegistrarId(transferData.getGainingRegistrarId()); // Finish projecting to now. - return (T) builder.build().cloneProjectedAtTime(now); + return (T) builder.build().cloneProjectedAtInstant(now); } - Optional newLastEppUpdateTime = Optional.empty(); + Optional newLastEppUpdateTime = Optional.empty(); // There is no transfer. Do any necessary autorenews for active domains. Builder builder = domain.asBuilder(); if (isBeforeOrAt(domain.getRegistrationExpirationTime(), now) - && END_OF_TIME.equals(domain.getDeletionTime())) { + && END_OF_TIME.equals(domain.getDeletionDateTime())) { // Autorenew by the number of years between the old expiration time and now. - DateTime lastAutorenewTime = + Instant lastAutorenewTime = leapSafeAddYears( domain.getRegistrationExpirationTime(), - new Interval(domain.getRegistrationExpirationTime(), now).toPeriod().getYears()); - DateTime newExpirationTime = lastAutorenewTime.plusYears(1); + YEARS.between(domain.getRegistrationExpirationTime().atZone(UTC), now.atZone(UTC))); + Instant newExpirationTime = plusYears(lastAutorenewTime, 1); builder - .setRegistrationExpirationTime(newExpirationTime) + .setRegistrationExpirationTime(toDateTime(newExpirationTime)) .addGracePeriod( GracePeriod.createForRecurrence( GracePeriodStatus.AUTO_RENEW, domain.getRepoId(), - lastAutorenewTime.plus(Tld.get(domain.getTld()).getAutoRenewGracePeriodLength()), + toDateTime(lastAutorenewTime) + .plus(Tld.get(domain.getTld()).getAutoRenewGracePeriodLength()), domain.getCurrentSponsorRegistrarId(), domain.getAutorenewBillingEvent())); newLastEppUpdateTime = Optional.of(lastAutorenewTime); @@ -551,10 +567,10 @@ && isBeforeOrAt(transferExpirationTime, now)) { // id, so we have to do the comparison instead of having one variable just storing the most // recent time. if (newLastEppUpdateTime.isPresent()) { - if (domain.getLastEppUpdateTime() == null + if (domain.getLastEppUpdateDateTime() == null || newLastEppUpdateTime.get().isAfter(domain.getLastEppUpdateTime())) { builder - .setLastEppUpdateTime(newLastEppUpdateTime.get()) + .setLastEppUpdateTime(toDateTime(newLastEppUpdateTime.get())) .setLastEppUpdateRegistrarId(domain.getCurrentSponsorRegistrarId()); } } @@ -567,8 +583,8 @@ && isBeforeOrAt(transferExpirationTime, now)) { } /** Return what the expiration time would be if the given number of years were added to it. */ - public static DateTime extendRegistrationWithCap( - DateTime now, DateTime currentExpirationTime, @Nullable Integer extendedRegistrationYears) { + public static Instant extendRegistrationWithCap( + Instant now, Instant currentExpirationTime, @Nullable Integer extendedRegistrationYears) { // We must cap registration at the max years (aka 10), even if that truncates the last year. return earliestOf( leapSafeAddYears( @@ -826,16 +842,16 @@ public B copyFrom(DomainBase domainBase) { .setDomainName(domainBase.getDomainName()) .setDeletePollMessage(domainBase.getDeletePollMessage()) .setDsData(domainBase.getDsData()) - .setDeletionTime(domainBase.getDeletionTime()) + .setDeletionTime(domainBase.getDeletionDateTime()) .setGracePeriods(domainBase.getGracePeriods()) .setIdnTableName(domainBase.getIdnTableName()) .setLastTransferTime(domainBase.getLastTransferTime()) .setLaunchNotice(domainBase.getLaunchNotice()) .setLastEppUpdateRegistrarId(domainBase.getLastEppUpdateRegistrarId()) - .setLastEppUpdateTime(domainBase.getLastEppUpdateTime()) + .setLastEppUpdateTime(domainBase.getLastEppUpdateDateTime()) .setNameservers(domainBase.getNameservers()) .setPersistedCurrentSponsorRegistrarId(domainBase.getPersistedCurrentSponsorRegistrarId()) - .setRegistrationExpirationTime(domainBase.getRegistrationExpirationTime()) + .setRegistrationExpirationTime(domainBase.getRegistrationExpirationDateTime()) .setRepoId(domainBase.getRepoId()) .setSmdId(domainBase.getSmdId()) .setSubordinateHosts(domainBase.getSubordinateHosts()) diff --git a/core/src/main/java/google/registry/model/domain/GracePeriodBase.java b/core/src/main/java/google/registry/model/domain/GracePeriodBase.java index a53abe45790..cca7742ed57 100644 --- a/core/src/main/java/google/registry/model/domain/GracePeriodBase.java +++ b/core/src/main/java/google/registry/model/domain/GracePeriodBase.java @@ -14,6 +14,8 @@ package google.registry.model.domain; +import static google.registry.util.DateTimeUtils.toInstant; + import google.registry.model.ImmutableObject; import google.registry.model.UnsafeSerializable; import google.registry.model.billing.BillingEvent; @@ -30,6 +32,7 @@ import jakarta.persistence.Enumerated; import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Transient; +import java.time.Instant; import org.joda.time.DateTime; /** Base class containing common fields and methods for {@link GracePeriod}. */ @@ -90,10 +93,15 @@ public String getDomainRepoId() { return domainRepoId; } - public DateTime getExpirationTime() { + @Deprecated + public DateTime getExpirationDateTime() { return expirationTime; } + public Instant getExpirationTime() { + return toInstant(expirationTime); + } + public String getRegistrarId() { return clientId; } diff --git a/core/src/main/java/google/registry/model/host/HostBase.java b/core/src/main/java/google/registry/model/host/HostBase.java index 8b70e49fc41..66480452b89 100644 --- a/core/src/main/java/google/registry/model/host/HostBase.java +++ b/core/src/main/java/google/registry/model/host/HostBase.java @@ -33,6 +33,7 @@ import jakarta.persistence.Convert; import jakarta.persistence.MappedSuperclass; import java.net.InetAddress; +import java.time.Instant; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; @@ -132,6 +133,11 @@ public HostBase cloneProjectedAtTime(DateTime now) { return this; } + @Override + public EppResource cloneProjectedAtInstant(Instant now) { + return this; + } + @Override public Builder asBuilder() { return new Builder<>(clone(this)); @@ -232,13 +238,13 @@ public B setLastTransferTime(DateTime lastTransferTime) { public B copyFrom(HostBase hostBase) { return setCreationRegistrarId(hostBase.getCreationRegistrarId()) .setCreationTime(hostBase.getCreationTime()) - .setDeletionTime(hostBase.getDeletionTime()) + .setDeletionTime(hostBase.getDeletionDateTime()) .setHostName(hostBase.getHostName()) .setInetAddresses(hostBase.getInetAddresses()) .setLastTransferTime(hostBase.getLastTransferTime()) .setLastSuperordinateChange(hostBase.getLastSuperordinateChange()) .setLastEppUpdateRegistrarId(hostBase.getLastEppUpdateRegistrarId()) - .setLastEppUpdateTime(hostBase.getLastEppUpdateTime()) + .setLastEppUpdateTime(hostBase.getLastEppUpdateDateTime()) .setPersistedCurrentSponsorRegistrarId(hostBase.getPersistedCurrentSponsorRegistrarId()) .setRepoId(hostBase.getRepoId()) .setSuperordinateDomain(hostBase.getSuperordinateDomain()) diff --git a/core/src/main/java/google/registry/model/poll/PollMessage.java b/core/src/main/java/google/registry/model/poll/PollMessage.java index 2e73951e3f3..16172266164 100644 --- a/core/src/main/java/google/registry/model/poll/PollMessage.java +++ b/core/src/main/java/google/registry/model/poll/PollMessage.java @@ -437,7 +437,7 @@ void postLoad() { .setTransferStatus(transferResponse.getTransferStatus()) .setTransferRequestTime(transferResponse.getTransferRequestTime()) .setPendingTransferExpirationTime( - transferResponse.getPendingTransferExpirationTime()) + transferResponse.getPendingTransferExpirationDateTime()) .setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime) .build(); } diff --git a/core/src/main/java/google/registry/model/tld/label/PremiumListDao.java b/core/src/main/java/google/registry/model/tld/label/PremiumListDao.java index 531eb833650..77e7a2bfb75 100644 --- a/core/src/main/java/google/registry/model/tld/label/PremiumListDao.java +++ b/core/src/main/java/google/registry/model/tld/label/PremiumListDao.java @@ -129,7 +129,11 @@ public static Optional getPremiumPrice(String premiumListName, String lab public static PremiumList save(String name, CurrencyUnit currencyUnit, List inputData) { checkArgument(!inputData.isEmpty(), "New premium list data cannot be empty"); - return save(PremiumListUtils.parseToPremiumList(name, currencyUnit, inputData)); + return tm().transact( + () -> + save( + PremiumListUtils.parseToPremiumList( + name, currencyUnit, inputData, tm().getTransactionTime()))); } /** Saves the given premium list (and its premium list entries) to Cloud SQL. */ diff --git a/core/src/main/java/google/registry/model/tld/label/PremiumListUtils.java b/core/src/main/java/google/registry/model/tld/label/PremiumListUtils.java index d25f9d61dc3..463be206d5f 100644 --- a/core/src/main/java/google/registry/model/tld/label/PremiumListUtils.java +++ b/core/src/main/java/google/registry/model/tld/label/PremiumListUtils.java @@ -14,8 +14,6 @@ package google.registry.model.tld.label; -import static org.joda.time.DateTimeZone.UTC; - import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import google.registry.model.tld.label.PremiumList.PremiumEntry; @@ -29,12 +27,12 @@ public class PremiumListUtils { public static PremiumList parseToPremiumList( - String name, CurrencyUnit currencyUnit, List inputData) { + String name, CurrencyUnit currencyUnit, List inputData, DateTime creationTime) { PremiumList partialPremiumList = new PremiumList.Builder() .setName(name) .setCurrency(currencyUnit) - .setCreationTimestamp(DateTime.now(UTC)) + .setCreationTimestamp(creationTime) .build(); ImmutableMap prices = partialPremiumList.parse(inputData); Map priceAmounts = Maps.transformValues(prices, PremiumEntry::getValue); diff --git a/core/src/main/java/google/registry/model/tld/label/ReservedList.java b/core/src/main/java/google/registry/model/tld/label/ReservedList.java index 4020254303e..2f2a0caa750 100644 --- a/core/src/main/java/google/registry/model/tld/label/ReservedList.java +++ b/core/src/main/java/google/registry/model/tld/label/ReservedList.java @@ -24,10 +24,10 @@ import static google.registry.persistence.transaction.QueryComposer.Comparator.EQ; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.util.CollectionUtils.nullToEmpty; -import static org.joda.time.DateTimeZone.UTC; import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Splitter; +import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.UncheckedExecutionException; @@ -47,7 +47,6 @@ import java.util.Map; import java.util.Optional; import javax.annotation.Nullable; -import org.joda.time.DateTime; /** * A list of reserved domain labels that are blocked from being registered for various reasons. @@ -234,7 +233,7 @@ public static ImmutableSet getReservationTypes(String label, St */ private static ImmutableSet getReservedListEntries( String label, String tldStr) { - DateTime startTime = DateTime.now(UTC); + Stopwatch stopwatch = Stopwatch.createStarted(); Tld tld = Tld.get(checkNotNull(tldStr, "tld must not be null")); ImmutableSet.Builder entriesBuilder = new ImmutableSet.Builder<>(); ImmutableSet.Builder metricMatchesBuilder = @@ -253,7 +252,7 @@ private static ImmutableSet getReservedListEntries( DomainLabelMetrics.recordReservedListCheckOutcome( tldStr, metricMatchesBuilder.build(), - DateTime.now(UTC).getMillis() - startTime.getMillis()); + stopwatch.elapsed().toMillis()); return entries; } diff --git a/core/src/main/java/google/registry/model/transfer/BaseTransferObject.java b/core/src/main/java/google/registry/model/transfer/BaseTransferObject.java index 9c55b52a1a9..e1a0a04c1bf 100644 --- a/core/src/main/java/google/registry/model/transfer/BaseTransferObject.java +++ b/core/src/main/java/google/registry/model/transfer/BaseTransferObject.java @@ -14,6 +14,8 @@ package google.registry.model.transfer; +import static google.registry.util.DateTimeUtils.toInstant; + import google.registry.model.Buildable.GenericBuilder; import google.registry.model.ImmutableObject; import google.registry.model.UnsafeSerializable; @@ -23,6 +25,7 @@ import jakarta.persistence.MappedSuperclass; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlTransient; +import java.time.Instant; import org.joda.time.DateTime; /** Fields common to {@link DomainTransferData} and {@link TransferResponse}. */ @@ -73,10 +76,15 @@ public String getLosingRegistrarId() { return losingClientId; } - public DateTime getPendingTransferExpirationTime() { + @Deprecated + public DateTime getPendingTransferExpirationDateTime() { return pendingTransferExpirationTime; } + public Instant getPendingTransferExpirationTime() { + return toInstant(pendingTransferExpirationTime); + } + /** Base class for builders of {@link BaseTransferObject} subclasses. */ public abstract static class Builder> extends GenericBuilder { diff --git a/core/src/main/java/google/registry/model/transfer/DomainTransferData.java b/core/src/main/java/google/registry/model/transfer/DomainTransferData.java index 7ecb17e2698..a56c3889d54 100644 --- a/core/src/main/java/google/registry/model/transfer/DomainTransferData.java +++ b/core/src/main/java/google/registry/model/transfer/DomainTransferData.java @@ -18,6 +18,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.CollectionUtils.nullToEmpty; +import static google.registry.util.DateTimeUtils.toInstant; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -41,6 +42,7 @@ import jakarta.persistence.Convert; import jakarta.persistence.Embeddable; import jakarta.persistence.Embedded; +import java.time.Instant; import java.util.Set; import javax.annotation.Nullable; import org.joda.time.DateTime; @@ -168,10 +170,16 @@ public Trid getTransferRequestTrid() { } @Nullable - public DateTime getTransferredRegistrationExpirationTime() { + @Deprecated + public DateTime getTransferredRegistrationExpirationDateTime() { return transferredRegistrationExpirationTime; } + @Nullable + public Instant getTransferredRegistrationExpirationTime() { + return toInstant(transferredRegistrationExpirationTime); + } + @Nullable public VKey getServerApproveBillingEvent() { return serverApproveBillingEvent; diff --git a/core/src/main/java/google/registry/persistence/transaction/JpaTransactionManagerImpl.java b/core/src/main/java/google/registry/persistence/transaction/JpaTransactionManagerImpl.java index f1633b7c189..4502a7d39e7 100644 --- a/core/src/main/java/google/registry/persistence/transaction/JpaTransactionManagerImpl.java +++ b/core/src/main/java/google/registry/persistence/transaction/JpaTransactionManagerImpl.java @@ -21,6 +21,7 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static google.registry.config.RegistryConfig.getHibernateAllowNestedTransactions; import static google.registry.persistence.transaction.DatabaseException.throwIfSqlException; +import static google.registry.util.DateTimeUtils.toDateTime; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import static java.util.AbstractMap.SimpleEntry; import static java.util.stream.Collectors.joining; @@ -61,6 +62,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.time.Instant; import java.util.Calendar; import java.util.Collections; import java.util.Date; @@ -340,6 +342,11 @@ public TransactionIsolationLevel getCurrentTransactionIsolationLevel() { @Override public DateTime getTransactionTime() { + return toDateTime(getTxTime()); + } + + @Override + public Instant getTxTime() { assertInTransaction(); TransactionInfo txnInfo = transactionInfo.get(); if (txnInfo.transactionTime == null) { @@ -746,7 +753,7 @@ private T detach(@Nullable T entity) { private static class TransactionInfo { EntityManager entityManager; boolean inTransaction = false; - DateTime transactionTime; + Instant transactionTime; Supplier idProvider; // The set of entity objects that have been either persisted (via insert()) or merged (via @@ -759,7 +766,7 @@ private static class TransactionInfo { private void start(Clock clock, Supplier idProvider) { checkArgumentNotNull(clock); inTransaction = true; - transactionTime = clock.nowUtc(); + transactionTime = clock.now(); this.idProvider = idProvider; } diff --git a/core/src/main/java/google/registry/persistence/transaction/TransactionManager.java b/core/src/main/java/google/registry/persistence/transaction/TransactionManager.java index 8cd63befe80..aa49bb9b784 100644 --- a/core/src/main/java/google/registry/persistence/transaction/TransactionManager.java +++ b/core/src/main/java/google/registry/persistence/transaction/TransactionManager.java @@ -20,6 +20,7 @@ import google.registry.model.ImmutableObject; import google.registry.persistence.PersistenceModule.TransactionIsolationLevel; import google.registry.persistence.VKey; +import java.time.Instant; import java.util.NoSuchElementException; import java.util.Optional; import java.util.concurrent.Callable; @@ -129,8 +130,12 @@ public interface TransactionManager { void reTransact(ThrowingRunnable work); /** Returns the time associated with the start of this particular transaction attempt. */ + @Deprecated DateTime getTransactionTime(); + /** Returns the Instant associated with the start of this particular transaction attempt. */ + Instant getTxTime(); + /** Persists a new entity in the database, throws exception if the entity already exists. */ void insert(Object entity); diff --git a/core/src/main/java/google/registry/rdap/RdapActionBase.java b/core/src/main/java/google/registry/rdap/RdapActionBase.java index 2b23be75044..94804bf0a17 100644 --- a/core/src/main/java/google/registry/rdap/RdapActionBase.java +++ b/core/src/main/java/google/registry/rdap/RdapActionBase.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN; import static google.registry.request.Actions.getPathForAction; +import static google.registry.util.DateTimeUtils.toInstant; import static google.registry.util.DomainNameUtils.canonicalizeHostname; import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; @@ -241,7 +242,7 @@ DeletedItemHandling getDeletedItemHandling() { * is authorized to do so. */ boolean isAuthorized(EppResource eppResource) { - return getRequestTime().isBefore(eppResource.getDeletionTime()) + return toInstant(getRequestTime()).isBefore(eppResource.getDeletionTime()) || (shouldIncludeDeleted() && rdapAuthorization.isAuthorizedForRegistrar( eppResource.getPersistedCurrentSponsorRegistrarId())); diff --git a/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java b/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java index 131c22f2f54..30047c3bda6 100644 --- a/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java +++ b/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java @@ -317,7 +317,7 @@ RdapDomain createRdapDomain(Domain domain, OutputDataType outputDataType) { .build(), Event.builder() .setEventAction(EventAction.EXPIRATION) - .setEventDate(domain.getRegistrationExpirationTime()) + .setEventDate(domain.getRegistrationExpirationDateTime()) .build(), // RDAP response profile section 1.5: // The topmost object in the RDAP response MUST contain an event of "eventAction" type @@ -358,7 +358,7 @@ RdapDomain createRdapDomain(Domain domain, OutputDataType outputDataType) { makeStatusValueList( allStatusValues, false, // isRedacted - domain.getDeletionTime().isBefore(getRequestTime())); + domain.getDeletionDateTime().isBefore(getRequestTime())); builder.statusBuilder().addAll(status); if (status.isEmpty()) { logger.atWarning().log( @@ -438,7 +438,7 @@ && replicaTm() makeStatusValueList( statuses.build(), false, // isRedacted - host.getDeletionTime().isBefore(getRequestTime()))); + host.getDeletionDateTime().isBefore(getRequestTime()))); } // For query responses - we MUST have all the ip addresses: RDAP Response Profile 4.2. @@ -752,7 +752,9 @@ private ImmutableList makeOptionalEvents(EppResource resource) { ImmutableList.Builder eventsBuilder = new ImmutableList.Builder<>(); DateTime creationTime = resource.getCreationTime(); DateTime lastChangeTime = - resource.getLastEppUpdateTime() == null ? creationTime : resource.getLastEppUpdateTime(); + resource.getLastEppUpdateDateTime() == null + ? creationTime + : resource.getLastEppUpdateDateTime(); // The order of the elements is stable - it's the order in which the enum elements are defined // in EventAction for (EventAction rdapEventAction : EventAction.values()) { diff --git a/core/src/main/java/google/registry/rde/DomainToXjcConverter.java b/core/src/main/java/google/registry/rde/DomainToXjcConverter.java index fe671a28def..89f4be1a01d 100644 --- a/core/src/main/java/google/registry/rde/DomainToXjcConverter.java +++ b/core/src/main/java/google/registry/rde/DomainToXjcConverter.java @@ -94,13 +94,13 @@ static XjcRdeDomain convertDomain(Domain model, RdeMode mode) { // identifying the end (expiration) of the domain name object's // registration period. This element MUST be present if the domain // name has been allocated. - bean.setExDate(model.getRegistrationExpirationTime()); + bean.setExDate(model.getRegistrationExpirationDateTime()); // o An OPTIONAL element that contains the date and time of // the most recent domain-name-object modification. This element // MUST NOT be present if the domain name object has never been // modified. - bean.setUpDate(model.getLastEppUpdateTime()); + bean.setUpDate(model.getLastEppUpdateDateTime()); // o An OPTIONAL element that contains the identifier of the // registrar that last updated the domain name object. This element @@ -228,8 +228,8 @@ private static XjcRdeDomainTransferDataType convertTransferData(DomainTransferDa bean.setReRr(RdeUtils.makeXjcRdeRrType(model.getGainingRegistrarId())); bean.setAcRr(RdeUtils.makeXjcRdeRrType(model.getLosingRegistrarId())); bean.setReDate(model.getTransferRequestTime()); - bean.setAcDate(model.getPendingTransferExpirationTime()); - bean.setExDate(model.getTransferredRegistrationExpirationTime()); + bean.setAcDate(model.getPendingTransferExpirationDateTime()); + bean.setExDate(model.getTransferredRegistrationExpirationDateTime()); return bean; } diff --git a/core/src/main/java/google/registry/rde/HostToXjcConverter.java b/core/src/main/java/google/registry/rde/HostToXjcConverter.java index 3f75703ee55..f822871aa2c 100644 --- a/core/src/main/java/google/registry/rde/HostToXjcConverter.java +++ b/core/src/main/java/google/registry/rde/HostToXjcConverter.java @@ -70,7 +70,7 @@ private static XjcRdeHost convertHostCommon( bean.setName(model.getHostName()); bean.setRoid(model.getRepoId()); bean.setCrDate(model.getCreationTime()); - bean.setUpDate(model.getLastEppUpdateTime()); + bean.setUpDate(model.getLastEppUpdateDateTime()); bean.setCrRr(RdeAdapter.convertRr(model.getCreationRegistrarId(), null)); bean.setUpRr(RdeAdapter.convertRr(model.getLastEppUpdateRegistrarId(), null)); bean.setCrRr(RdeAdapter.convertRr(model.getCreationRegistrarId(), null)); diff --git a/core/src/main/java/google/registry/tools/CreateAnchorTenantCommand.java b/core/src/main/java/google/registry/tools/CreateAnchorTenantCommand.java index 4e392cb162c..c48da2a8c05 100644 --- a/core/src/main/java/google/registry/tools/CreateAnchorTenantCommand.java +++ b/core/src/main/java/google/registry/tools/CreateAnchorTenantCommand.java @@ -19,18 +19,17 @@ import static google.registry.model.tld.Tlds.findTldForNameOrThrow; import static google.registry.pricing.PricingEngineProxy.getDomainCreateCost; import static google.registry.util.StringGenerator.DEFAULT_PASSWORD_LENGTH; -import static org.joda.time.DateTimeZone.UTC; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.net.InternetDomainName; import com.google.template.soy.data.SoyMapData; import google.registry.tools.soy.CreateAnchorTenantSoyInfo; +import google.registry.util.Clock; import google.registry.util.StringGenerator; import jakarta.inject.Inject; import jakarta.inject.Named; import org.joda.money.Money; -import org.joda.time.DateTime; /** A command to create a new anchor tenant domain. */ @Parameters(separators = " =", commandDescription = "Provision a domain for an anchor tenant.") @@ -76,6 +75,8 @@ final class CreateAnchorTenantCommand extends MutatingEppToolCommand { @Named("base64StringGenerator") StringGenerator passwordGenerator; + @Inject Clock clock; + @Override protected void initMutatingEppToolCommand() { checkArgument(superuser, "This command must be run as a superuser."); @@ -86,7 +87,7 @@ protected void initMutatingEppToolCommand() { Money cost = null; if (fee) { - cost = getDomainCreateCost(domainName, DateTime.now(UTC), DEFAULT_ANCHOR_TENANT_PERIOD_YEARS); + cost = getDomainCreateCost(domainName, clock.nowUtc(), DEFAULT_ANCHOR_TENANT_PERIOD_YEARS); } setSoyTemplate(CreateAnchorTenantSoyInfo.getInstance(), diff --git a/core/src/main/java/google/registry/tools/CreateDomainCommand.java b/core/src/main/java/google/registry/tools/CreateDomainCommand.java index 101e5017727..a9f32807d21 100644 --- a/core/src/main/java/google/registry/tools/CreateDomainCommand.java +++ b/core/src/main/java/google/registry/tools/CreateDomainCommand.java @@ -17,18 +17,17 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName; -import static org.joda.time.DateTimeZone.UTC; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.template.soy.data.SoyMapData; import google.registry.model.pricing.PremiumPricingEngine.DomainPrices; import google.registry.tools.soy.DomainCreateSoyInfo; +import google.registry.util.Clock; import google.registry.util.StringGenerator; import jakarta.inject.Inject; import jakarta.inject.Named; import org.joda.money.Money; -import org.joda.time.DateTime; /** A command to create a new domain via EPP. */ @Parameters(separators = " =", commandDescription = "Create a new domain via EPP.") @@ -53,6 +52,8 @@ final class CreateDomainCommand extends CreateOrUpdateDomainCommand { @Named("base64StringGenerator") StringGenerator passwordGenerator; + @Inject Clock clock; + private static final int PASSWORD_LENGTH = 16; @Override @@ -64,7 +65,7 @@ protected void initMutatingEppToolCommand() { for (String domain : domains) { String currency = null; String cost = null; - DomainPrices prices = getPricesForDomainName(domain, DateTime.now(UTC)); + DomainPrices prices = getPricesForDomainName(domain, clock.nowUtc()); // Check if the domain is premium and set the fee on the create command if so. if (prices.isPremium()) { diff --git a/core/src/main/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java b/core/src/main/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java index 469cd2c027f..f8a4f619d7d 100644 --- a/core/src/main/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java +++ b/core/src/main/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java @@ -21,7 +21,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static google.registry.util.RegistrarUtils.normalizeRegistrarName; import static java.nio.charset.StandardCharsets.US_ASCII; -import static org.joda.time.DateTimeZone.UTC; import com.beust.jcommander.Parameter; import com.google.common.base.Ascii; @@ -37,6 +36,7 @@ import google.registry.tools.params.PathParameter.InputFile; import google.registry.tools.params.StringListParameter; import google.registry.util.CidrAddressBlock; +import google.registry.util.Clock; import jakarta.inject.Inject; import java.nio.file.Files; import java.nio.file.Path; @@ -56,6 +56,8 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand { @Inject CertificateChecker certificateChecker; + @Inject Clock clock; + @Parameter(description = "Client identifier of the registrar account", required = true) List mainParameters; @@ -272,7 +274,7 @@ protected void initRegistrarCommand() {} @Override protected final void init() throws Exception { initRegistrarCommand(); - DateTime now = DateTime.now(UTC); + DateTime now = clock.nowUtc(); for (String clientId : mainParameters) { Registrar oldRegistrar = getOldRegistrar(clientId); Registrar.Builder builder = diff --git a/core/src/main/java/google/registry/tools/CreateReservedListCommand.java b/core/src/main/java/google/registry/tools/CreateReservedListCommand.java index 7cbe44c3572..878e8ebf8dc 100644 --- a/core/src/main/java/google/registry/tools/CreateReservedListCommand.java +++ b/core/src/main/java/google/registry/tools/CreateReservedListCommand.java @@ -18,7 +18,6 @@ import static google.registry.model.tld.Tlds.assertTldExists; import static google.registry.util.ListNamingUtils.convertFilePathToName; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.joda.time.DateTimeZone.UTC; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; @@ -26,6 +25,8 @@ import com.google.common.base.Splitter; import com.google.common.base.Strings; import google.registry.model.tld.label.ReservedList; +import google.registry.util.Clock; +import jakarta.inject.Inject; import java.nio.file.Files; import java.util.List; import org.joda.time.DateTime; @@ -34,6 +35,8 @@ @Parameters(separators = " =", commandDescription = "Create a ReservedList.") final class CreateReservedListCommand extends CreateOrUpdateReservedListCommand { + @Inject Clock clock; + @VisibleForTesting static final String INVALID_FORMAT_ERROR_MESSAGE = "The name must be in the format {tld|common}_list-name " @@ -51,7 +54,7 @@ protected String prompt() throws Exception { if (!override) { validateListName(name); } - DateTime now = DateTime.now(UTC); + DateTime now = clock.nowUtc(); List allLines = Files.readAllLines(input, UTF_8); reservedList = new ReservedList.Builder() diff --git a/core/src/main/java/google/registry/tools/GenerateDnsReportCommand.java b/core/src/main/java/google/registry/tools/GenerateDnsReportCommand.java index f4aad1d544a..88e0a367901 100644 --- a/core/src/main/java/google/registry/tools/GenerateDnsReportCommand.java +++ b/core/src/main/java/google/registry/tools/GenerateDnsReportCommand.java @@ -81,7 +81,7 @@ String generate() { .list()); for (Domain domain : domains) { // Skip deleted domains and domains that don't get published to DNS. - if (isBeforeOrAt(domain.getDeletionTime(), now) || !domain.shouldPublishToDns()) { + if (isBeforeOrAt(domain.getDeletionDateTime(), now) || !domain.shouldPublishToDns()) { continue; } write(domain); @@ -90,7 +90,7 @@ String generate() { Iterable nameservers = tm().transact(() -> tm().loadAllOf(Host.class)); for (Host nameserver : nameservers) { // Skip deleted hosts and external hosts. - if (isBeforeOrAt(nameserver.getDeletionTime(), now) + if (isBeforeOrAt(nameserver.getDeletionDateTime(), now) || nameserver.getInetAddresses().isEmpty()) { continue; } diff --git a/core/src/main/java/google/registry/tools/GenerateZoneFilesCommand.java b/core/src/main/java/google/registry/tools/GenerateZoneFilesCommand.java index b08ca56f482..6fd1fb55f49 100644 --- a/core/src/main/java/google/registry/tools/GenerateZoneFilesCommand.java +++ b/core/src/main/java/google/registry/tools/GenerateZoneFilesCommand.java @@ -15,7 +15,6 @@ package google.registry.tools; import static google.registry.model.tld.Tlds.assertTldsExist; -import static org.joda.time.DateTimeZone.UTC; import static org.joda.time.Duration.standardMinutes; import com.beust.jcommander.Parameter; @@ -23,6 +22,8 @@ import com.google.common.collect.ImmutableMap; import google.registry.tools.params.DateParameter; import google.registry.tools.server.GenerateZoneFilesAction; +import google.registry.util.Clock; +import jakarta.inject.Inject; import java.io.IOException; import java.util.List; import java.util.Map; @@ -43,7 +44,9 @@ final class GenerateZoneFilesCommand implements CommandWithConnection { description = "The date to generate the file for (defaults to today, or yesterday if run " + "before 00:02).", validateWith = DateParameter.class) - private DateTime exportDate = DateTime.now(UTC).minus(standardMinutes(2)).withTimeAtStartOfDay(); + private DateTime exportDate; + + @Inject Clock clock; private ServiceConnection connection; @@ -54,6 +57,9 @@ public void setConnection(ServiceConnection connection) { @Override public void run() throws IOException { + if (exportDate == null) { + exportDate = clock.nowUtc().minus(standardMinutes(2)).withTimeAtStartOfDay(); + } assertTldsExist(mainParameters); ImmutableMap params = ImmutableMap.of( "tlds", mainParameters, diff --git a/core/src/main/java/google/registry/tools/GetHistoryEntriesCommand.java b/core/src/main/java/google/registry/tools/GetHistoryEntriesCommand.java index 394cbc702df..9c2938d0573 100644 --- a/core/src/main/java/google/registry/tools/GetHistoryEntriesCommand.java +++ b/core/src/main/java/google/registry/tools/GetHistoryEntriesCommand.java @@ -17,7 +17,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME; -import static org.joda.time.DateTimeZone.UTC; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; @@ -26,7 +25,9 @@ import google.registry.model.reporting.HistoryEntryDao; import google.registry.persistence.VKey; import google.registry.tools.CommandUtilities.ResourceType; +import google.registry.util.Clock; import google.registry.xml.XmlTransformer; +import jakarta.inject.Inject; import org.joda.time.DateTime; /** Command to show history entries. */ @@ -35,6 +36,8 @@ commandDescription = "Show history entries that occurred in a given time range") final class GetHistoryEntriesCommand implements Command { + @Inject Clock clock; + @Parameter( names = {"-a", "--after"}, description = "Only show history entries that occurred at or after this time") @@ -58,7 +61,7 @@ public void run() { checkArgument( type != null && uniqueId != null, "If either of 'type' or 'id' are set then both must be"); - VKey parentKey = type.getKey(uniqueId, DateTime.now(UTC)); + VKey parentKey = type.getKey(uniqueId, clock.nowUtc()); historyEntries = HistoryEntryDao.loadHistoryObjectsForResource(parentKey, after, before); } else { historyEntries = HistoryEntryDao.loadAllHistoryObjects(after, before); diff --git a/core/src/main/java/google/registry/tools/RenewDomainCommand.java b/core/src/main/java/google/registry/tools/RenewDomainCommand.java index 81f26263454..838db13ce5d 100644 --- a/core/src/main/java/google/registry/tools/RenewDomainCommand.java +++ b/core/src/main/java/google/registry/tools/RenewDomainCommand.java @@ -81,7 +81,7 @@ protected void initMutatingEppToolCommand() SoyMapData soyMapData = new SoyMapData( "domainName", domain.getDomainName(), - "expirationDate", domain.getRegistrationExpirationTime().toString(DATE_FORMATTER), + "expirationDate", domain.getRegistrationExpirationDateTime().toString(DATE_FORMATTER), "period", String.valueOf(period)); if (requestedByRegistrar != null) { diff --git a/core/src/main/java/google/registry/tools/UniformRapidSuspensionCommand.java b/core/src/main/java/google/registry/tools/UniformRapidSuspensionCommand.java index 1f3368ef2c4..77290a85292 100644 --- a/core/src/main/java/google/registry/tools/UniformRapidSuspensionCommand.java +++ b/core/src/main/java/google/registry/tools/UniformRapidSuspensionCommand.java @@ -163,7 +163,7 @@ protected void initMutatingEppToolCommand() domain.getDomainName(), "expirationDate", domain - .getRegistrationExpirationTime() + .getRegistrationExpirationDateTime() .toString(DateTimeFormat.forPattern("YYYY-MM-dd")), // period is the number of years to renew the registration for "period", diff --git a/core/src/main/java/google/registry/tools/UnrenewDomainCommand.java b/core/src/main/java/google/registry/tools/UnrenewDomainCommand.java index 29613a8ecaa..06866ebca3e 100644 --- a/core/src/main/java/google/registry/tools/UnrenewDomainCommand.java +++ b/core/src/main/java/google/registry/tools/UnrenewDomainCommand.java @@ -99,8 +99,9 @@ protected void init() throws UnsupportedEncodingException { domainsWithDisallowedStatusesBuilder.putAll( domainName, Sets.intersection(domain.get().getStatusValues(), DISALLOWED_STATUSES)); if (isBeforeOrAt( - leapSafeSubtractYears(domain.get().getRegistrationExpirationTime(), period), now)) { - domainsExpiringTooSoonBuilder.put(domainName, domain.get().getRegistrationExpirationTime()); + leapSafeSubtractYears(domain.get().getRegistrationExpirationDateTime(), period), now)) { + domainsExpiringTooSoonBuilder.put( + domainName, domain.get().getRegistrationExpirationDateTime()); } } @@ -143,7 +144,7 @@ protected String prompt() { DateTime now = clock.nowUtc(); for (String domainName : mainParameters) { Domain domain = ForeignKeyUtils.loadResource(Domain.class, domainName, now).get(); - DateTime previousTime = domain.getRegistrationExpirationTime(); + DateTime previousTime = domain.getRegistrationExpirationDateTime(); DateTime newTime = leapSafeSubtractYears(previousTime, period); resultBuilder.append( String.format( @@ -179,12 +180,12 @@ private void unrenewDomain(String domainName) { "Domain %s has prohibited status values", domainName); checkState( - leapSafeSubtractYears(domain.getRegistrationExpirationTime(), period).isAfter(now), + leapSafeSubtractYears(domain.getRegistrationExpirationDateTime(), period).isAfter(now), "Domain %s expires too soon", domainName); DateTime newExpirationTime = - leapSafeSubtractYears(domain.getRegistrationExpirationTime(), period); + leapSafeSubtractYears(domain.getRegistrationExpirationDateTime(), period); DomainHistory domainHistory = new DomainHistory.Builder() .setDomain(domain) diff --git a/core/src/main/java/google/registry/tools/UpdatePremiumListCommand.java b/core/src/main/java/google/registry/tools/UpdatePremiumListCommand.java index 4e8d7ed3169..8c04977164c 100644 --- a/core/src/main/java/google/registry/tools/UpdatePremiumListCommand.java +++ b/core/src/main/java/google/registry/tools/UpdatePremiumListCommand.java @@ -24,12 +24,16 @@ import google.registry.model.tld.label.PremiumList; import google.registry.model.tld.label.PremiumListDao; import google.registry.model.tld.label.PremiumListUtils; +import google.registry.util.Clock; +import jakarta.inject.Inject; import java.nio.file.Files; /** Command to safely update {@link PremiumList} in Database for a given TLD. */ @Parameters(separators = " =", commandDescription = "Update a PremiumList in Database.") class UpdatePremiumListCommand extends CreateOrUpdatePremiumListCommand { + @Inject Clock clock; + @Parameter( names = {"-d", "--dry_run"}, description = "Does not execute the entity mutation") @@ -62,7 +66,8 @@ protected String prompt() throws Exception { inputData = Files.readAllLines(inputFile, UTF_8); checkArgument(!inputData.isEmpty(), "New premium list data cannot be empty"); currency = existingList.getCurrency(); - PremiumList updatedPremiumList = PremiumListUtils.parseToPremiumList(name, currency, inputData); + PremiumList updatedPremiumList = + PremiumListUtils.parseToPremiumList(name, currency, inputData, clock.nowUtc()); if (!existingList .getLabelsToPrices() .entrySet() diff --git a/core/src/main/java/google/registry/tools/UpdateRecurrenceCommand.java b/core/src/main/java/google/registry/tools/UpdateRecurrenceCommand.java index 87120148275..73a300ae885 100644 --- a/core/src/main/java/google/registry/tools/UpdateRecurrenceCommand.java +++ b/core/src/main/java/google/registry/tools/UpdateRecurrenceCommand.java @@ -16,7 +16,9 @@ import static com.google.common.base.Preconditions.checkArgument; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.util.DateTimeUtils.END_INSTANT; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.toDateTime; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; @@ -31,6 +33,7 @@ import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry.HistoryEntryId; import google.registry.model.transfer.TransferStatus; +import java.time.Instant; import java.util.List; import java.util.Optional; import javax.annotation.Nullable; @@ -161,7 +164,7 @@ private ImmutableList internalExecute() { private ImmutableMap loadDomainsAndRecurrences() { ImmutableMap.Builder result = new ImmutableMap.Builder<>(); - DateTime now = tm().getTransactionTime(); + Instant now = tm().getTxTime(); for (String domainName : mainParameters) { Domain domain = ForeignKeyUtils.loadResource(Domain.class, domainName, now) @@ -171,7 +174,7 @@ private ImmutableMap loadDomainsAndRecurrences() { String.format( "Domain %s does not exist or has been deleted", domainName))); checkArgument( - domain.getDeletionTime().equals(END_OF_TIME), + domain.getDeletionTime().equals(END_INSTANT), "Domain %s has already had a deletion time set", domainName); checkArgument( @@ -184,7 +187,7 @@ private ImmutableMap loadDomainsAndRecurrences() { domainAutorenewEndTime.ifPresent( endTime -> checkArgument( - endTime.isAfter(now), + endTime.isAfter(toDateTime(now)), "Domain %s autorenew ended prior to now at %s", domainName, endTime)); diff --git a/core/src/main/java/google/registry/ui/server/console/ConsoleDumDownloadAction.java b/core/src/main/java/google/registry/ui/server/console/ConsoleDumDownloadAction.java index e056d116ad0..c609a7d023b 100644 --- a/core/src/main/java/google/registry/ui/server/console/ConsoleDumDownloadAction.java +++ b/core/src/main/java/google/registry/ui/server/console/ConsoleDumDownloadAction.java @@ -16,7 +16,6 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.request.Action.Method.GET; -import static org.joda.time.DateTimeZone.UTC; import com.google.common.collect.ImmutableList; import com.google.common.flogger.FluentLogger; @@ -35,7 +34,6 @@ import java.io.IOException; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; -import org.joda.time.DateTime; @Action( service = Service.CONSOLE, @@ -86,7 +84,7 @@ protected void getHandler(User user) { .setHeader("Cache-Control", "max-age=86400"); // 86400 seconds = 1 day consoleApiParams .response() - .setDateHeader("Expires", DateTime.now(UTC).withTimeAtStartOfDay().plusDays(1)); + .setDateHeader("Expires", clock.nowUtc().withTimeAtStartOfDay().plusDays(1)); try (var writer = consoleApiParams.response().getWriter()) { CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT); diff --git a/core/src/test/java/google/registry/batch/DeleteExpiredDomainsActionTest.java b/core/src/test/java/google/registry/batch/DeleteExpiredDomainsActionTest.java index 6fe8694964c..0315dedd67f 100644 --- a/core/src/test/java/google/registry/batch/DeleteExpiredDomainsActionTest.java +++ b/core/src/test/java/google/registry/batch/DeleteExpiredDomainsActionTest.java @@ -24,6 +24,7 @@ import static google.registry.testing.DatabaseHelper.persistActiveDomain; import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.plusDays; import com.google.common.collect.ImmutableSet; import google.registry.flows.DaggerEppTestComponent; @@ -117,7 +118,7 @@ void test_deletesOnlyExpiredDomain() { assertThat(loadByEntity(notYetExpiredDomain)).isEqualTo(notYetExpiredDomain); Domain reloadedExpiredDomain = loadByEntity(pendingExpirationDomain); assertThat(reloadedExpiredDomain.getStatusValues()).contains(PENDING_DELETE); - assertThat(reloadedExpiredDomain.getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35)); + assertThat(reloadedExpiredDomain.getDeletionTime()).isEqualTo(plusDays(clock.now(), 35)); } @Test diff --git a/core/src/test/java/google/registry/batch/DeleteProberDataActionTest.java b/core/src/test/java/google/registry/batch/DeleteProberDataActionTest.java index 9c11baa01d4..7304c07adbc 100644 --- a/core/src/test/java/google/registry/batch/DeleteProberDataActionTest.java +++ b/core/src/test/java/google/registry/batch/DeleteProberDataActionTest.java @@ -26,7 +26,7 @@ import static google.registry.testing.DatabaseHelper.persistDeletedDomain; import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted; import static google.registry.testing.DatabaseHelper.persistResource; -import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.END_INSTANT; import static org.joda.time.DateTimeZone.UTC; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -45,8 +45,10 @@ import google.registry.persistence.transaction.JpaTestExtensions; import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension; import google.registry.testing.DatabaseHelper; +import google.registry.testing.FakeClock; import google.registry.testing.SystemPropertyExtension; import google.registry.util.RegistryEnvironment; +import java.time.Instant; import java.util.Optional; import java.util.Set; import org.joda.money.Money; @@ -61,9 +63,11 @@ class DeleteProberDataActionTest { private static final DateTime DELETION_TIME = DateTime.parse("2010-01-01T00:00:00.000Z"); + private final FakeClock clock = new FakeClock(DateTime.now(UTC)); + @RegisterExtension final JpaIntegrationTestExtension jpa = - new JpaTestExtensions.Builder().buildIntegrationTestExtension(); + new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension(); @RegisterExtension final SystemPropertyExtension systemPropertyExtension = new SystemPropertyExtension(); @@ -93,7 +97,9 @@ void beforeEach() { } private void resetAction() { - action = new DeleteProberDataAction(false, ImmutableSet.of(), Optional.empty(), "TheRegistrar"); + action = + new DeleteProberDataAction( + false, ImmutableSet.of(), Optional.empty(), "TheRegistrar", clock); } @AfterEach @@ -123,7 +129,8 @@ void test_deletesAllInBatches() throws Exception { Set oaEntities = persistLotsOfDomains("oa-canary.test"); // Create action with batch size of 3 DeleteProberDataAction batchedAction = - new DeleteProberDataAction(false, ImmutableSet.of(), Optional.of(3), "TheRegistrar"); + new DeleteProberDataAction( + false, ImmutableSet.of(), Optional.of(3), "TheRegistrar", clock); batchedAction.run(); assertAllAbsent(ibEntities); assertAllAbsent(oaEntities); @@ -201,7 +208,7 @@ void testSuccess_activeDomain_isSoftDeleted() throws Exception { .setCreationTimeForTest(DateTime.now(UTC).minusYears(1)) .build()); action.run(); - DateTime timeAfterDeletion = DateTime.now(UTC); + Instant timeAfterDeletion = Instant.now(); assertThat(ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", timeAfterDeletion)) .isEmpty(); assertThat(loadByEntity(domain).getDeletionTime()).isLessThan(timeAfterDeletion); @@ -217,7 +224,7 @@ void testSuccess_activeDomain_doubleMapSoftDeletes() throws Exception { .setCreationTimeForTest(DateTime.now(UTC).minusYears(1)) .build()); action.run(); - DateTime timeAfterDeletion = DateTime.now(UTC); + Instant timeAfterDeletion = Instant.now(); resetAction(); action.run(); assertThat(ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", timeAfterDeletion)) @@ -237,7 +244,7 @@ void test_recentlyCreatedDomain_isntDeletedYet() throws Exception { Optional domain = ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", DateTime.now(UTC)); assertThat(domain).isPresent(); - assertThat(domain.get().getDeletionTime()).isEqualTo(END_OF_TIME); + assertThat(domain.get().getDeletionTime()).isEqualTo(END_INSTANT); } @Test @@ -250,7 +257,7 @@ void testDryRun_doesntSoftDeleteData() throws Exception { .build()); action.isDryRun = true; action.run(); - assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(END_OF_TIME); + assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(END_INSTANT); } @Test diff --git a/core/src/test/java/google/registry/batch/SendExpiringCertificateNotificationEmailActionTest.java b/core/src/test/java/google/registry/batch/SendExpiringCertificateNotificationEmailActionTest.java index d944a3e0953..42ac0ff4a6a 100644 --- a/core/src/test/java/google/registry/batch/SendExpiringCertificateNotificationEmailActionTest.java +++ b/core/src/test/java/google/registry/batch/SendExpiringCertificateNotificationEmailActionTest.java @@ -97,7 +97,8 @@ void beforeEach() throws Exception { EXPIRATION_WARNING_EMAIL_SUBJECT_TEXT, sendEmailService, certificateChecker, - response); + response, + clock); sampleRegistrar = persistResource(createRegistrar("clientId", "sampleRegistrar", null, null).build()); diff --git a/core/src/test/java/google/registry/beam/resave/ResaveAllEppResourcesPipelineTest.java b/core/src/test/java/google/registry/beam/resave/ResaveAllEppResourcesPipelineTest.java index c87216be024..b9d8f59a547 100644 --- a/core/src/test/java/google/registry/beam/resave/ResaveAllEppResourcesPipelineTest.java +++ b/core/src/test/java/google/registry/beam/resave/ResaveAllEppResourcesPipelineTest.java @@ -25,6 +25,8 @@ import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources; import static google.registry.testing.DatabaseHelper.persistDomainWithPendingTransfer; import static google.registry.testing.DatabaseHelper.persistNewRegistrars; +import static google.registry.util.DateTimeUtils.plusYears; +import static google.registry.util.DateTimeUtils.toInstant; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -113,11 +115,12 @@ void testPipeline_autorenewedDomain() { DateTime now = fakeClock.nowUtc(); Domain domain = persistDomainWithDependentResources("domain", "tld", now, now, now.plusYears(1)); - assertThat(domain.getRegistrationExpirationTime()).isEqualTo(now.plusYears(1)); + assertThat(domain.getRegistrationExpirationTime()).isEqualTo(plusYears(toInstant(now), 1)); fakeClock.advanceBy(Duration.standardDays(500)); runPipeline(); Domain postPipeline = loadByEntity(domain); - assertThat(postPipeline.getRegistrationExpirationTime()).isEqualTo(now.plusYears(2)); + assertThat(postPipeline.getRegistrationExpirationTime()) + .isEqualTo(plusYears(toInstant(now), 2)); } @Test diff --git a/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java b/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java index fb45f347354..3d3540ab885 100644 --- a/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java +++ b/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java @@ -488,7 +488,7 @@ void testDomainDeletion_outsideAddGracePeriod_showsRedemptionPeriod() throws Exc // Make sure that in the future, the domain expiration is unchanged after deletion Domain clonedDomain = domain.cloneProjectedAtTime(deleteTime.plusYears(5)); - assertThat(clonedDomain.getRegistrationExpirationTime()).isEqualTo(createTime.plusYears(2)); + assertThat(clonedDomain.getRegistrationExpirationDateTime()).isEqualTo(createTime.plusYears(2)); } @Test diff --git a/core/src/test/java/google/registry/flows/FlowTestCase.java b/core/src/test/java/google/registry/flows/FlowTestCase.java index ba2b31f61af..4daf414b2d1 100644 --- a/core/src/test/java/google/registry/flows/FlowTestCase.java +++ b/core/src/test/java/google/registry/flows/FlowTestCase.java @@ -182,7 +182,7 @@ private static ImmutableMap canonicalizeGracePeriods( GracePeriod.create( entry.getKey().getType(), entry.getKey().getDomainRepoId(), - entry.getKey().getExpirationTime(), + entry.getKey().getExpirationDateTime(), entry.getKey().getRegistrarId(), null, 1L), diff --git a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java index f1ae4f4855f..6c402def637 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java @@ -361,7 +361,7 @@ private void assertSuccessfulCreate( .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setTargetId(getUniqueIdFromCommand()) .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setRecurrenceEndTime(END_OF_TIME) .setDomainHistory(historyEntry) .setRenewalPriceBehavior(expectedRenewalPriceBehavior) @@ -397,7 +397,7 @@ private void assertSuccessfulCreate( new PollMessage.Autorenew.Builder() .setTargetId(domain.getDomainName()) .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntry) .build()); @@ -1720,7 +1720,7 @@ private void assertPollMessagesWithCollisionOneTime(Domain domain) { new PollMessage.Autorenew.Builder() .setTargetId(domain.getDomainName()) .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntry) .build(), @@ -1853,7 +1853,7 @@ void testSuccess_customLogicIsCalled_andSavesExtraEntity() throws Exception { new PollMessage.Autorenew.Builder() .setTargetId(domain.getDomainName()) .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntry) .build(), diff --git a/core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java index 223293b1f5f..9b3b2060b58 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java @@ -376,7 +376,7 @@ void testSuccess_updatedEppUpdateTimeAfterPendingRedemption() throws Exception { runFlowAssertResponse(loadFile("domain_delete_response_pending.xml")); Domain domain = reloadResourceByForeignKey(); - DateTime redemptionEndTime = domain.getLastEppUpdateTime().plusDays(3); + DateTime redemptionEndTime = domain.getLastEppUpdateDateTime().plusDays(3); Domain domainAtRedemptionTime = domain.cloneProjectedAtTime(redemptionEndTime); assertAboutDomains() .that(domainAtRedemptionTime) @@ -418,7 +418,7 @@ private void doSuccessfulTest_noAddGracePeriod( null)); // We should see exactly one poll message, which is for the autorenew 1 month in the future. assertPollMessages(createAutorenewPollMessage("TheRegistrar").build()); - DateTime expectedExpirationTime = domain.getRegistrationExpirationTime().minusYears(2); + DateTime expectedExpirationTime = domain.getRegistrationExpirationDateTime().minusYears(2); clock.advanceOneMilli(); runFlowAssertResponse(loadFile(responseFilename, substitutions)); Domain resource = reloadResourceByForeignKey(); @@ -462,7 +462,7 @@ private void assertDeletionPollMessageFor(Domain domain, String expectedMessage) // There should be a future poll message at the deletion time. The previous autorenew poll // message should now be deleted. assertAboutDomains().that(domain).hasDeletePollMessage(); - DateTime deletionTime = domain.getDeletionTime(); + DateTime deletionTime = domain.getDeletionDateTime(); assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).isEmpty(); assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(1); assertThat(domain.getDeletePollMessage()) @@ -496,7 +496,7 @@ void testSuccess_autorenewPollMessageIsNotDeleted() throws Exception { runFlowAssertResponse(loadFile("domain_delete_response_pending.xml")); // There should now be two poll messages; one for the delete of the domain (in the future), and // another for the unacked autorenew messages. - DateTime deletionTime = reloadResourceByForeignKey().getDeletionTime(); + DateTime deletionTime = reloadResourceByForeignKey().getDeletionDateTime(); assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).hasSize(1); assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(2); } @@ -613,7 +613,7 @@ void testSuccess_pendingTransfer() throws Exception { .isEqualTo(Trid.create("transferClient-trid", "transferServer-trid")); assertThat(panData.getActionResult()).isFalse(); // There should be a future poll message to the losing registrar at the deletion time. - DateTime deletionTime = domain.getDeletionTime(); + DateTime deletionTime = domain.getDeletionDateTime(); assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).isEmpty(); assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(1); assertOnlyBillingEventIsClosedAutorenew("TheRegistrar"); diff --git a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java index 6694e221d74..cdbb9e478fd 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java @@ -247,7 +247,7 @@ private void doSuccessfulTest( @Nullable Money renewalPrice) throws Exception { assertMutatingFlow(true); - DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime(); + DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationDateTime(); DateTime newExpiration = currentExpiration.plusYears(renewalYears); runFlowAssertResponse( CommitMode.LIVE, userPrivileges, loadFile(responseFilename, substitutions)); @@ -303,7 +303,7 @@ private void doSuccessfulTest( .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setTargetId(getUniqueIdFromCommand()) .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setRecurrenceEndTime(END_OF_TIME) .setDomainHistory(historyEntryDomainRenew) .build()); @@ -313,7 +313,7 @@ private void doSuccessfulTest( new PollMessage.Autorenew.Builder() .setTargetId(getUniqueIdFromCommand()) .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setAutorenewEndTime(END_OF_TIME) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntryDomainRenew) @@ -817,7 +817,7 @@ void testSuccess_autorenewPollMessageIsNotDeleted() throws Exception { new PollMessage.Autorenew.Builder() .setTargetId(getUniqueIdFromCommand()) .setRegistrarId("TheRegistrar") - .setEventTime(reloadResourceByForeignKey().getRegistrationExpirationTime()) + .setEventTime(reloadResourceByForeignKey().getRegistrationExpirationDateTime()) .setAutorenewEndTime(END_OF_TIME) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntryDomainRenew) diff --git a/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java index 69c28ee896a..35eeb139945 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java @@ -201,7 +201,7 @@ void testSuccess_expiryStillInFuture_notExtended() throws Exception { new PollMessage.Autorenew.Builder() .setTargetId("example.tld") .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setAutorenewEndTime(END_OF_TIME) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntryDomainRestore) @@ -269,7 +269,7 @@ void testSuccess_expiryInPast_extendedByOneYear() throws Exception { new PollMessage.Autorenew.Builder() .setTargetId("example.tld") .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setAutorenewEndTime(END_OF_TIME) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntryDomainRestore) diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferApproveFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferApproveFlowTest.java index aafa9387236..30a9339e3a2 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferApproveFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferApproveFlowTest.java @@ -148,7 +148,8 @@ private void assertTransferApproved(Domain domain, DomainTransferData oldTransfe .copyConstantFieldsToBuilder() .setTransferStatus(TransferStatus.CLIENT_APPROVED) .setPendingTransferExpirationTime(clock.nowUtc()) - .setTransferredRegistrationExpirationTime(domain.getRegistrationExpirationTime()) + .setTransferredRegistrationExpirationTime( + domain.getRegistrationExpirationDateTime()) .build()); } @@ -216,7 +217,7 @@ private void runSuccessfulFlowWithAssertions( // should be one at the current time to the gaining registrar, as well as one at the domain's // autorenew time. assertThat(getPollMessages(domain, "NewRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1); - assertThat(getPollMessages(domain, "NewRegistrar", domain.getRegistrationExpirationTime())) + assertThat(getPollMessages(domain, "NewRegistrar", domain.getRegistrationExpirationDateTime())) .hasSize(2); PollMessage gainingTransferPollMessage = @@ -225,11 +226,11 @@ private void runSuccessfulFlowWithAssertions( getOnlyPollMessage( domain, "NewRegistrar", - domain.getRegistrationExpirationTime(), + domain.getRegistrationExpirationDateTime(), PollMessage.Autorenew.class); assertThat(gainingTransferPollMessage.getEventTime()).isEqualTo(clock.nowUtc()); assertThat(gainingAutorenewPollMessage.getEventTime()) - .isEqualTo(domain.getRegistrationExpirationTime()); + .isEqualTo(domain.getRegistrationExpirationDateTime()); DomainTransferResponse transferResponse = gainingTransferPollMessage .getResponseData() @@ -239,7 +240,7 @@ private void runSuccessfulFlowWithAssertions( .collect(onlyElement()); assertThat(transferResponse.getTransferStatus()).isEqualTo(TransferStatus.CLIENT_APPROVED); assertThat(transferResponse.getExtendedRegistrationExpirationTime()) - .isEqualTo(domain.getRegistrationExpirationTime()); + .isEqualTo(domain.getRegistrationExpirationDateTime()); PendingActionNotificationResponse panData = gainingTransferPollMessage .getResponseData() @@ -294,9 +295,9 @@ private void assertHistoryEntriesContainBillingEventsAndGracePeriods( .build(), getGainingClientAutorenewEvent() .asBuilder() - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setRecurrenceLastExpansion( - domain.getRegistrationExpirationTime().minusYears(1)) + domain.getRegistrationExpirationDateTime().minusYears(1)) .setDomainHistory(historyEntryTransferApproved) .build())) .toArray(BillingBase[]::new)); @@ -332,9 +333,9 @@ private void assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods .build(), getGainingClientAutorenewEvent() .asBuilder() - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setRecurrenceLastExpansion( - domain.getRegistrationExpirationTime().minusYears(1)) + domain.getRegistrationExpirationDateTime().minusYears(1)) .setDomainHistory(historyEntryTransferApproved) .build())) .toArray(BillingBase[]::new)); @@ -349,7 +350,7 @@ private void doSuccessfulTest(String tld, String commandFilename, String expecte tld, commandFilename, expectedXmlFilename, - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), 1); } @@ -821,7 +822,7 @@ void testSuccess_superuserExtension_transferPeriodZero() throws Exception { "tld", "domain_transfer_approve.xml", "domain_transfer_approve_response_zero_period.xml", - domain.getRegistrationExpirationTime()); + domain.getRegistrationExpirationDateTime()); assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods(); } @@ -854,7 +855,7 @@ void testSuccess_superuserExtension_transferPeriodZero_autorenewGraceActive() th "tld", "domain_transfer_approve.xml", "domain_transfer_approve_response_zero_period_autorenew_grace.xml", - domain.getRegistrationExpirationTime()); + domain.getRegistrationExpirationDateTime()); assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods(); } diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java index c7b62116bb8..ea5ff9e16c3 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java @@ -114,7 +114,7 @@ private void doSuccessfulTest(String commandFilename) throws Exception { // Setup done; run the test. assertMutatingFlow(true); - DateTime originalExpirationTime = domain.getRegistrationExpirationTime(); + DateTime originalExpirationTime = domain.getRegistrationExpirationDateTime(); ImmutableSet originalGracePeriods = domain.getGracePeriods(); DomainTransferData originalTransferData = domain.getTransferData(); runFlowAssertResponse(loadFile("domain_transfer_cancel_response.xml")); diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java index 523120f4ade..b96a4f41223 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java @@ -143,7 +143,8 @@ void testSuccess_tenYears() throws Exception { persistResource( domain .asBuilder() - .setRegistrationExpirationTime(domain.getRegistrationExpirationTime().plusYears(9)) + .setRegistrationExpirationTime( + domain.getRegistrationExpirationDateTime().plusYears(9)) .build()); doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response_10_years.xml", 1); } @@ -233,7 +234,7 @@ void testSuccess_serverApproved_afterAutorenews() throws Exception { // Set the clock to just past the extended registration time. We'd expect the domain to have // auto-renewed once, but the transfer query response should be the same. clock.setTo(EXTENDED_REGISTRATION_EXPIRATION_TIME.plusMillis(1)); - assertThat(domain.cloneProjectedAtTime(clock.nowUtc()).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(clock.nowUtc()).getRegistrationExpirationDateTime()) .isEqualTo(EXTENDED_REGISTRATION_EXPIRATION_TIME.plusYears(1)); doSuccessfulTest( "domain_transfer_query.xml", "domain_transfer_query_response_server_approved.xml", 2); diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java index f26b460d497..e3bac621677 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java @@ -88,7 +88,7 @@ private void doSuccessfulTest(String commandFilename, String expectedXmlFilename assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1); // Setup done; run the test. assertMutatingFlow(true); - DateTime originalExpirationTime = domain.getRegistrationExpirationTime(); + DateTime originalExpirationTime = domain.getRegistrationExpirationDateTime(); ImmutableSet originalGracePeriods = domain.getGracePeriods(); DomainTransferData originalTransferData = domain.getTransferData(); runFlowAssertResponse(loadFile(expectedXmlFilename)); diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java index 70ad4517e37..7afa97cd697 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java @@ -244,7 +244,8 @@ private void assertTransferApproved( .setTransferPeriod(expectedPeriod) .setTransferStatus(TransferStatus.SERVER_APPROVED) .setPendingTransferExpirationTime(automaticTransferTime) - .setTransferredRegistrationExpirationTime(domain.getRegistrationExpirationTime()) + .setTransferredRegistrationExpirationTime( + domain.getRegistrationExpirationDateTime()) // Server-approve entity fields should all be nulled out. .build()); } @@ -542,7 +543,7 @@ private void doSuccessfulTest( doSuccessfulTest( commandFilename, expectedXmlFilename, - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), substitutions, Optional.empty()); } @@ -551,7 +552,9 @@ private void doSuccessfulTest(String commandFilename, String expectedXmlFilename throws Exception { clock.advanceOneMilli(); doSuccessfulTest( - commandFilename, expectedXmlFilename, domain.getRegistrationExpirationTime().plusYears(1)); + commandFilename, + expectedXmlFilename, + domain.getRegistrationExpirationDateTime().plusYears(1)); } private void doSuccessfulSuperuserExtensionTest( @@ -812,7 +815,7 @@ void testSuccess_superuserExtension_zeroPeriod_nonZeroAutomaticTransferLength() doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_nonzero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "5"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -826,7 +829,7 @@ void testSuccess_superuserExtension_zeroPeriod_zeroAutomaticTransferLength() thr doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_zero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -841,7 +844,7 @@ void testSuccess_superuserExtension_nonZeroPeriod_nonZeroAutomaticTransferLength doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_one_year_period_nonzero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), ImmutableMap.of("PERIOD", "1", "AUTOMATIC_TRANSFER_LENGTH", "5"), Optional.empty(), Period.create(1, Unit.YEARS), @@ -873,7 +876,7 @@ void testSuccess_superuserExtension_zeroPeriod_autorenewGraceActive() throws Exc doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_autorenew_grace.xml", - domain.getRegistrationExpirationTime(), + domain.getRegistrationExpirationDateTime(), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -922,7 +925,7 @@ void testSuccess_superuserExtension_clientTransferProhibited() throws Exception doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_zero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -939,7 +942,7 @@ void testSuccess_superuserExtension_serverTransferProhibited() throws Exception doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_zero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -977,7 +980,7 @@ void testSuccess_customLogicFee_std_v1() throws Exception { doSuccessfulTest( "domain_transfer_request_separate_fees.xml", "domain_transfer_request_response_fees.xml", - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), new ImmutableMap.Builder() .put("DOMAIN", "expensive-domain.foo") .put("YEARS", "1") @@ -1409,7 +1412,7 @@ void testSuccess_bulkPricingName_zeroPeriod() throws Exception { doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_zero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -2024,7 +2027,7 @@ void testSuccess_customLogicFee_v06() throws Exception { doSuccessfulTest( "domain_transfer_request_separate_fees.xml", "domain_transfer_request_response_fees.xml", - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), new ImmutableMap.Builder() .put("DOMAIN", "expensive-domain.foo") .put("YEARS", "1") diff --git a/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java b/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java index 084cd41924b..2103b06d441 100644 --- a/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java +++ b/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java @@ -256,7 +256,7 @@ void testSuccess_nameUnchanged_superordinateDomainWasTransferred() throws Except .and() .hasPersistedCurrentSponsorRegistrarId("NewRegistrar") .and() - .hasLastTransferTime(domain.getTransferData().getPendingTransferExpirationTime()) + .hasLastTransferTime(domain.getTransferData().getPendingTransferExpirationDateTime()) .and() .hasOnlyOneHistoryEntryWhich() .hasType(HistoryEntry.Type.HOST_UPDATE); diff --git a/core/src/test/java/google/registry/model/domain/DomainTest.java b/core/src/test/java/google/registry/model/domain/DomainTest.java index e6e81d9a1df..ad04eb1d088 100644 --- a/core/src/test/java/google/registry/model/domain/DomainTest.java +++ b/core/src/test/java/google/registry/model/domain/DomainTest.java @@ -31,6 +31,10 @@ import static google.registry.testing.SqlHelper.saveRegistrar; import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME; +import static google.registry.util.DateTimeUtils.minusDays; +import static google.registry.util.DateTimeUtils.plusDays; +import static google.registry.util.DateTimeUtils.plusYears; +import static google.registry.util.DateTimeUtils.toDateTime; import static org.joda.money.CurrencyUnit.USD; import static org.joda.time.DateTimeZone.UTC; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -67,6 +71,8 @@ import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationWithCoverageExtension; import google.registry.testing.DatabaseHelper; import google.registry.testing.FakeClock; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Optional; import org.joda.money.Money; import org.joda.time.DateTime; @@ -386,7 +392,7 @@ private void assertTransferred( .isEqualTo(TransferStatus.SERVER_APPROVED); assertThat(domain.getCurrentSponsorRegistrarId()).isEqualTo("TheRegistrar"); assertThat(domain.getLastTransferTime()).isEqualTo(fakeClock.nowUtc().plusDays(1)); - assertThat(domain.getRegistrationExpirationTime()).isEqualTo(newExpirationTime); + assertThat(domain.getRegistrationExpirationDateTime()).isEqualTo(newExpirationTime); assertThat(domain.getAutorenewBillingEvent()).isEqualTo(newAutorenewEvent); } @@ -479,56 +485,57 @@ void testExpiredTransfer_autoRenewBeforeTransfer() { } private void setupPendingTransferDomain( - DateTime oldExpirationTime, DateTime transferRequestTime, DateTime transferSuccessTime) { + Instant oldExpirationTime, Instant transferRequestTime, Instant transferSuccessTime) { domain = domain .asBuilder() - .setRegistrationExpirationTime(oldExpirationTime) + .setRegistrationExpirationTime(toDateTime(oldExpirationTime)) .setTransferData( domain .getTransferData() .asBuilder() .setTransferStatus(TransferStatus.PENDING) - .setTransferRequestTime(transferRequestTime) - .setPendingTransferExpirationTime(transferSuccessTime) + .setTransferRequestTime(toDateTime(transferRequestTime)) + .setPendingTransferExpirationTime(toDateTime(transferSuccessTime)) .build()) - .setLastEppUpdateTime(transferRequestTime) + .setLastEppUpdateTime(toDateTime(transferRequestTime)) .setLastEppUpdateRegistrarId(domain.getTransferData().getGainingRegistrarId()) .build(); } @Test void testEppLastUpdateTimeAndClientId_autoRenewBeforeTransferSuccess() { - DateTime now = fakeClock.nowUtc(); - DateTime transferRequestDateTime = now.plusDays(1); - DateTime autorenewDateTime = now.plusDays(3); - DateTime transferSuccessDateTime = now.plusDays(5); + Instant now = fakeClock.now(); + Instant transferRequestDateTime = plusDays(now, 1); + Instant autorenewDateTime = plusDays(now, 3); + Instant transferSuccessDateTime = plusDays(now, 5); setupPendingTransferDomain(autorenewDateTime, transferRequestDateTime, transferSuccessDateTime); - Domain beforeAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.minusDays(1)); + Domain beforeAutoRenew = domain.cloneProjectedAtInstant(minusDays(autorenewDateTime, 1)); assertThat(beforeAutoRenew.getLastEppUpdateTime()).isEqualTo(transferRequestDateTime); assertThat(beforeAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar"); // If autorenew happens before transfer succeeds(before transfer grace period starts as well), // lastEppUpdateRegistrarId should still be the current sponsor client id - Domain afterAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.plusDays(1)); + Domain afterAutoRenew = domain.cloneProjectedAtInstant(plusDays(autorenewDateTime, 1)); assertThat(afterAutoRenew.getLastEppUpdateTime()).isEqualTo(autorenewDateTime); assertThat(afterAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo("NewRegistrar"); } @Test void testEppLastUpdateTimeAndClientId_autoRenewAfterTransferSuccess() { - DateTime now = fakeClock.nowUtc(); - DateTime transferRequestDateTime = now.plusDays(1); - DateTime autorenewDateTime = now.plusDays(3); - DateTime transferSuccessDateTime = now.plusDays(5); + Instant now = fakeClock.now(); + Instant transferRequestDateTime = plusDays(now, 1); + Instant autorenewDateTime = plusDays(now, 3); + Instant transferSuccessDateTime = plusDays(now, 5); setupPendingTransferDomain(autorenewDateTime, transferRequestDateTime, transferSuccessDateTime); - Domain beforeAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.minusDays(1)); + Domain beforeAutoRenew = domain.cloneProjectedAtInstant(minusDays(autorenewDateTime, 1)); assertThat(beforeAutoRenew.getLastEppUpdateTime()).isEqualTo(transferRequestDateTime); assertThat(beforeAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar"); - Domain afterTransferSuccess = domain.cloneProjectedAtTime(transferSuccessDateTime.plusDays(1)); + Domain afterTransferSuccess = + domain.cloneProjectedAtInstant(plusDays(transferSuccessDateTime, 1)); assertThat(afterTransferSuccess.getLastEppUpdateTime()).isEqualTo(transferSuccessDateTime); assertThat(afterTransferSuccess.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar"); } @@ -552,11 +559,11 @@ void testEppLastUpdateTimeAndClientId_isSetCorrectlyWithNullPreviousValue() { setupUnmodifiedDomain(autorenewDateTime); Domain beforeAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.minusDays(1)); - assertThat(beforeAutoRenew.getLastEppUpdateTime()).isEqualTo(null); + assertThat(beforeAutoRenew.getLastEppUpdateDateTime()).isEqualTo(null); assertThat(beforeAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo(null); Domain afterAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.plusDays(1)); - assertThat(afterAutoRenew.getLastEppUpdateTime()).isEqualTo(autorenewDateTime); + assertThat(afterAutoRenew.getLastEppUpdateDateTime()).isEqualTo(autorenewDateTime); assertThat(afterAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo("NewRegistrar"); } @@ -633,9 +640,9 @@ void testGracePeriodsByType() { @Test void testRenewalsHappenAtExpiration() { - Domain renewed = domain.cloneProjectedAtTime(domain.getRegistrationExpirationTime()); + Domain renewed = domain.cloneProjectedAtInstant(domain.getRegistrationExpirationTime()); assertThat(renewed.getRegistrationExpirationTime()) - .isEqualTo(domain.getRegistrationExpirationTime().plusYears(1)); + .isEqualTo(plusYears(domain.getRegistrationExpirationTime(), 1)); assertThat(renewed.getLastEppUpdateTime()).isEqualTo(domain.getRegistrationExpirationTime()); assertThat(getOnlyElement(renewed.getGracePeriods()).getType()) .isEqualTo(GracePeriodStatus.AUTO_RENEW); @@ -656,15 +663,16 @@ void testRenewalsDontHappenOnFebruary29() { .setRegistrationExpirationTime(DateTime.parse("2004-02-29T22:00:00.0Z")) .build(); Domain renewed = - domain.cloneProjectedAtTime(domain.getRegistrationExpirationTime().plusYears(4)); - assertThat(renewed.getRegistrationExpirationTime().getDayOfMonth()).isEqualTo(28); + domain.cloneProjectedAtInstant(plusYears(domain.getRegistrationExpirationTime(), 4)); + assertThat(renewed.getRegistrationExpirationTime().atZone(ZoneOffset.UTC).getDayOfMonth()) + .isEqualTo(28); } @Test void testMultipleAutoRenews() { // Change the registry so that renewal costs change every year to make sure we are using the // autorenew time as the lookup time for the cost. - DateTime oldExpirationTime = domain.getRegistrationExpirationTime(); + DateTime oldExpirationTime = domain.getRegistrationExpirationDateTime(); persistResource( Tld.get("com") .asBuilder() @@ -680,9 +688,10 @@ void testMultipleAutoRenews() { .build()) .build()); Domain renewedThreeTimes = domain.cloneProjectedAtTime(oldExpirationTime.plusYears(2)); - assertThat(renewedThreeTimes.getRegistrationExpirationTime()) + assertThat(renewedThreeTimes.getRegistrationExpirationDateTime()) .isEqualTo(oldExpirationTime.plusYears(3)); - assertThat(renewedThreeTimes.getLastEppUpdateTime()).isEqualTo(oldExpirationTime.plusYears(2)); + assertThat(renewedThreeTimes.getLastEppUpdateDateTime()) + .isEqualTo(oldExpirationTime.plusYears(2)); assertThat(renewedThreeTimes.getGracePeriods()) .containsExactly( GracePeriod.createForRecurrence( @@ -730,7 +739,7 @@ void testClone_doNotExtendExpirationOnDeletedDomain() { .setDeletionTime(now.minusDays(10)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE, StatusValue.INACTIVE)) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(now.minusDays(1)); } @@ -746,7 +755,7 @@ void testClone_doNotExtendExpirationOnFutureDeletedDomain() { .setDeletionTime(now.plusDays(20)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE, StatusValue.INACTIVE)) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(now.plusDays(1)); } @@ -773,7 +782,7 @@ void testClone_extendsExpirationForExpiredTransferredDomain() { .setTransferData(transferData) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(newExpiration); } @@ -801,7 +810,7 @@ void testClone_extendsExpirationForNonExpiredTransferredDomain() { .setTransferData(transferData) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(newExpiration); } @@ -843,7 +852,7 @@ void testClone_removesBulkTokenFromTransferredDomain() { assertThat(domain.getCurrentBulkToken()).isPresent(); Domain clonedDomain = domain.cloneProjectedAtTime(now); - assertThat(clonedDomain.getRegistrationExpirationTime()).isEqualTo(newExpiration); + assertThat(clonedDomain.getRegistrationExpirationDateTime()).isEqualTo(newExpiration); assertThat(clonedDomain.getCurrentBulkToken()).isEmpty(); } @@ -868,7 +877,7 @@ void testClone_doesNotExtendExpirationForPendingTransfer() { .setTransferData(transferData) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(previousExpiration); } @@ -906,7 +915,7 @@ void testClone_doesNotRemoveBulkTokenForPendingTransfer() { .build()); Domain clonedDomain = domain.cloneProjectedAtTime(now); - assertThat(clonedDomain.getRegistrationExpirationTime()).isEqualTo(previousExpiration); + assertThat(clonedDomain.getRegistrationExpirationDateTime()).isEqualTo(previousExpiration); assertThat(clonedDomain.getCurrentBulkToken().get()).isEqualTo(allocationToken.createVKey()); } @@ -943,8 +952,8 @@ void testClone_transferDuringAutorenew() { .setAutorenewBillingEvent(recurrenceBillKey) .build()); Domain clone = domain.cloneProjectedAtTime(now); - assertThat(clone.getRegistrationExpirationTime()) - .isEqualTo(domain.getRegistrationExpirationTime().plusYears(1)); + assertThat(clone.getRegistrationExpirationDateTime()) + .isEqualTo(domain.getRegistrationExpirationDateTime().plusYears(1)); // Transferring removes the AUTORENEW grace period and adds a TRANSFER grace period assertThat(getOnlyElement(clone.getGracePeriods()).getType()) .isEqualTo(GracePeriodStatus.TRANSFER); diff --git a/core/src/test/java/google/registry/model/domain/GracePeriodTest.java b/core/src/test/java/google/registry/model/domain/GracePeriodTest.java index bc79c043adc..8453d28ddc2 100644 --- a/core/src/test/java/google/registry/model/domain/GracePeriodTest.java +++ b/core/src/test/java/google/registry/model/domain/GracePeriodTest.java @@ -68,7 +68,7 @@ void testSuccess_forBillingEvent() { assertThat(gracePeriod.getBillingEvent()).isEqualTo(onetime.createVKey()); assertThat(gracePeriod.getBillingRecurrence()).isNull(); assertThat(gracePeriod.getRegistrarId()).isEqualTo("TheRegistrar"); - assertThat(gracePeriod.getExpirationTime()).isEqualTo(now.plusDays(1)); + assertThat(gracePeriod.getExpirationDateTime()).isEqualTo(now.plusDays(1)); assertThat(gracePeriod.hasBillingEvent()).isTrue(); } @@ -82,7 +82,7 @@ void testSuccess_forRecurrence() { assertThat(gracePeriod.getBillingEvent()).isNull(); assertThat(gracePeriod.getBillingRecurrence()).isEqualTo(recurrenceKey); assertThat(gracePeriod.getRegistrarId()).isEqualTo("TheRegistrar"); - assertThat(gracePeriod.getExpirationTime()).isEqualTo(now.plusDays(1)); + assertThat(gracePeriod.getExpirationDateTime()).isEqualTo(now.plusDays(1)); assertThat(gracePeriod.hasBillingEvent()).isTrue(); } @@ -96,7 +96,7 @@ void testSuccess_createWithoutBillingEvent() { assertThat(gracePeriod.getBillingEvent()).isNull(); assertThat(gracePeriod.getBillingRecurrence()).isNull(); assertThat(gracePeriod.getRegistrarId()).isEqualTo("TheRegistrar"); - assertThat(gracePeriod.getExpirationTime()).isEqualTo(now); + assertThat(gracePeriod.getExpirationDateTime()).isEqualTo(now); assertThat(gracePeriod.hasBillingEvent()).isFalse(); } diff --git a/core/src/test/java/google/registry/model/tld/label/PremiumListUtilsTest.java b/core/src/test/java/google/registry/model/tld/label/PremiumListUtilsTest.java index 7abd8f5cbb9..add2245f5d3 100644 --- a/core/src/test/java/google/registry/model/tld/label/PremiumListUtilsTest.java +++ b/core/src/test/java/google/registry/model/tld/label/PremiumListUtilsTest.java @@ -17,20 +17,27 @@ import static com.google.common.truth.Truth.assertThat; import static google.registry.model.tld.label.PremiumListUtils.parseToPremiumList; import static org.joda.money.CurrencyUnit.USD; +import static org.joda.time.DateTimeZone.UTC; import static org.junit.jupiter.api.Assertions.assertThrows; import com.google.common.collect.ImmutableList; import java.math.BigDecimal; +import org.joda.time.DateTime; import org.junit.jupiter.api.Test; /** Unit tests for {@link PremiumListUtils}. */ class PremiumListUtilsTest { + private static final DateTime SAMPLE_TIME = DateTime.now(UTC); + @Test void parseInputToPremiumList_works() { PremiumList premiumList = parseToPremiumList( - "testlist", USD, ImmutableList.of("foo,USD 99.50", "bar,USD 30", "baz,USD 10")); + "testlist", + USD, + ImmutableList.of("foo,USD 99.50", "bar,USD 30", "baz,USD 10"), + SAMPLE_TIME); assertThat(premiumList.getName()).isEqualTo("testlist"); assertThat(premiumList.getLabelsToPrices()) .containsExactly("foo", twoDigits(99.50), "bar", twoDigits(30), "baz", twoDigits(10)); @@ -45,7 +52,8 @@ void parseInputToPremiumList_throwsOnInconsistentCurrencies() { parseToPremiumList( "testlist", USD, - ImmutableList.of("foo,USD 99.50", "bar,USD 30", "baz,JPY 990"))); + ImmutableList.of("foo,USD 99.50", "bar,USD 30", "baz,JPY 990"), + SAMPLE_TIME)); assertThat(thrown).hasMessageThat().isEqualTo("The currency unit must be USD"); } diff --git a/core/src/test/java/google/registry/reporting/icann/IcannReportingStagerTest.java b/core/src/test/java/google/registry/reporting/icann/IcannReportingStagerTest.java index 77092e5e1d9..4e2714781c3 100644 --- a/core/src/test/java/google/registry/reporting/icann/IcannReportingStagerTest.java +++ b/core/src/test/java/google/registry/reporting/icann/IcannReportingStagerTest.java @@ -16,6 +16,7 @@ import static com.google.common.truth.Truth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.joda.time.DateTimeZone.UTC; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -31,15 +32,18 @@ import google.registry.bigquery.BigqueryUtils.TableType; import google.registry.gcs.GcsUtils; import google.registry.reporting.icann.IcannReportingModule.ReportType; +import google.registry.testing.FakeClock; import google.registry.testing.FakeResponse; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import org.joda.time.DateTime; import org.joda.time.YearMonth; import org.junit.jupiter.api.Test; /** Unit tests for {@link google.registry.reporting.icann.IcannReportingStager}. */ class IcannReportingStagerTest { + private final FakeClock clock = new FakeClock(DateTime.now(UTC)); private BigqueryConnection bigquery = mock(BigqueryConnection.class); FakeResponse response = new FakeResponse(); private YearMonth yearMonth = new YearMonth(2017, 6); @@ -63,7 +67,7 @@ private void setUpBigquery() { when(bigquery.startQuery(any(String.class), any(DestinationTable.class))) .thenReturn(fakeFuture()); DestinationTable.Builder tableBuilder = - new DestinationTable.Builder() + new DestinationTable.Builder(clock) .datasetId("testdataset") .type(TableType.TABLE) .name("tablename") diff --git a/core/src/test/java/google/registry/testing/AbstractEppResourceSubject.java b/core/src/test/java/google/registry/testing/AbstractEppResourceSubject.java index baebec91be9..a8a039c4df3 100644 --- a/core/src/test/java/google/registry/testing/AbstractEppResourceSubject.java +++ b/core/src/test/java/google/registry/testing/AbstractEppResourceSubject.java @@ -148,15 +148,15 @@ public And hasExactlyStatusValues(StatusValue... statusValues) { } public And hasDeletionTime(DateTime deletionTime) { - return hasValue(deletionTime, actual.getDeletionTime(), "getDeletionTime()"); + return hasValue(deletionTime, actual.getDeletionDateTime(), "getDeletionTime()"); } public And hasLastEppUpdateTime(DateTime lastUpdateTime) { - return hasValue(lastUpdateTime, actual.getLastEppUpdateTime(), "has lastEppUpdateTime"); + return hasValue(lastUpdateTime, actual.getLastEppUpdateDateTime(), "has lastEppUpdateTime"); } public And hasLastEppUpdateTimeAtLeast(DateTime before) { - DateTime lastEppUpdateTime = actual.getLastEppUpdateTime(); + DateTime lastEppUpdateTime = actual.getLastEppUpdateDateTime(); check("getLastEppUpdateTime()").that(lastEppUpdateTime).isAtLeast(before); return andChainer(); } diff --git a/core/src/test/java/google/registry/testing/DomainSubject.java b/core/src/test/java/google/registry/testing/DomainSubject.java index 0036528baee..507a548c9c1 100644 --- a/core/src/test/java/google/registry/testing/DomainSubject.java +++ b/core/src/test/java/google/registry/testing/DomainSubject.java @@ -78,7 +78,7 @@ public And hasCurrentSponsorRegistrarId(String registrarId) { public And hasRegistrationExpirationTime(DateTime expiration) { return hasValue( - expiration, actual.getRegistrationExpirationTime(), "getRegistrationExpirationTime()"); + expiration, actual.getRegistrationExpirationDateTime(), "getRegistrationExpirationTime()"); } public And hasLastTransferTime(DateTime lastTransferTime) { diff --git a/core/src/test/java/google/registry/tools/CommandTestCase.java b/core/src/test/java/google/registry/tools/CommandTestCase.java index e2060506d3f..d298a0239a0 100644 --- a/core/src/test/java/google/registry/tools/CommandTestCase.java +++ b/core/src/test/java/google/registry/tools/CommandTestCase.java @@ -80,6 +80,18 @@ public final void beforeEachCommandTestCase() throws Exception { RegistryToolEnvironment.UNITTEST.setup(systemPropertyExtension); command = newCommandInstance(); + // Inject the fake clock into the command if it has a clock field. + for (Class c = command.getClass(); c != null; c = c.getSuperclass()) { + try { + java.lang.reflect.Field clockField = c.getDeclaredField("clock"); + clockField.setAccessible(true); + clockField.set(command, fakeClock); + break; + } catch (NoSuchFieldException e) { + // Fall through. + } + } + // Capture standard output/error. Use a single-byte encoding to emulate platforms where default // charset is not UTF_8. oldStdout = System.out; diff --git a/core/src/test/java/google/registry/tools/CreatePremiumListCommandTest.java b/core/src/test/java/google/registry/tools/CreatePremiumListCommandTest.java index 947fdffe816..ace6ce512e4 100644 --- a/core/src/test/java/google/registry/tools/CreatePremiumListCommandTest.java +++ b/core/src/test/java/google/registry/tools/CreatePremiumListCommandTest.java @@ -54,7 +54,6 @@ void commandRun_successCreateList() throws Exception { // since the old entity is always null and file cannot be empty, the prompt will NOT be "No entity // changes to apply." void commandPrompt_successStageNewEntity() throws Exception { - CreatePremiumListCommand command = new CreatePremiumListCommand(); command.inputFile = Paths.get(premiumTermsPath); command.currencyUnit = "USD"; command.prompt(); @@ -63,7 +62,6 @@ void commandPrompt_successStageNewEntity() throws Exception { @Test void commandPrompt_successStageNewEntityWithOverride() throws Exception { - CreatePremiumListCommand command = new CreatePremiumListCommand(); String alterTld = "override"; command.inputFile = Paths.get(premiumTermsPath); command.override = true; @@ -75,7 +73,6 @@ void commandPrompt_successStageNewEntityWithOverride() throws Exception { @Test void commandPrompt_failureNoInputFile() { - CreatePremiumListCommand command = new CreatePremiumListCommand(); assertThrows(NullPointerException.class, command::prompt); } @@ -83,7 +80,6 @@ void commandPrompt_failureNoInputFile() { void commandPrompt_failurePremiumListAlreadyExists() { String randomStr = "random"; DatabaseHelper.createTld(randomStr); - CreatePremiumListCommand command = new CreatePremiumListCommand(); command.name = randomStr; command.currencyUnit = "USD"; IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, command::prompt); @@ -92,7 +88,6 @@ void commandPrompt_failurePremiumListAlreadyExists() { @Test void commandPrompt_failureMismatchedTldFileName_noOverride() throws Exception { - CreatePremiumListCommand command = new CreatePremiumListCommand(); String fileName = "random"; Path tmpPath = tmpDir.resolve(String.format("%s.txt", fileName)); Files.write(new byte[0], tmpPath.toFile()); @@ -111,7 +106,6 @@ void commandPrompt_failureMismatchedTldFileName_noOverride() throws Exception { @Test void commandPrompt_failureMismatchedTldName_noOverride() { - CreatePremiumListCommand command = new CreatePremiumListCommand(); String fileName = "random"; command.name = fileName; command.currencyUnit = "USD"; diff --git a/core/src/test/java/google/registry/tools/CreateReservedListCommandTest.java b/core/src/test/java/google/registry/tools/CreateReservedListCommandTest.java index 4575b073119..acbb6c679d2 100644 --- a/core/src/test/java/google/registry/tools/CreateReservedListCommandTest.java +++ b/core/src/test/java/google/registry/tools/CreateReservedListCommandTest.java @@ -162,7 +162,6 @@ private void runNameTestWithOverride(String name) throws Exception { @Test void testStageEntityChange_succeeds() throws Exception { - CreateReservedListCommand command = new CreateReservedListCommand(); // file content is populated in @BeforeEach of CreateOrUpdateReservedListCommandTestCase.java command.input = Paths.get(reservedTermsPath); command.init(); @@ -176,7 +175,6 @@ void testStageEntityChange_succeeds() throws Exception { void testStageEntityChange_succeedsWithEmptyFile() throws Exception { Path tmpPath = tmpDir.resolve("xn--q9jyb4c_common-tmp.txt"); Files.write(new byte[0], tmpPath.toFile()); - CreateReservedListCommand command = new CreateReservedListCommand(); command.input = tmpPath; command.init(); assertThat(command.prompt()).contains("reservedListMap=[]"); diff --git a/core/src/test/java/google/registry/tools/UnrenewDomainCommandTest.java b/core/src/test/java/google/registry/tools/UnrenewDomainCommandTest.java index 9f4d161c882..378231a46af 100644 --- a/core/src/test/java/google/registry/tools/UnrenewDomainCommandTest.java +++ b/core/src/test/java/google/registry/tools/UnrenewDomainCommandTest.java @@ -78,12 +78,12 @@ void test_unrenewTwoDomains_worksSuccessfully() throws Exception { assertThat( ForeignKeyUtils.loadResource(Domain.class, "foo.tld", fakeClock.nowUtc()) .get() - .getRegistrationExpirationTime()) + .getRegistrationExpirationDateTime()) .isEqualTo(DateTime.parse("2019-12-06T13:55:01.001Z")); assertThat( ForeignKeyUtils.loadResource(Domain.class, "bar.tld", fakeClock.nowUtc()) .get() - .getRegistrationExpirationTime()) + .getRegistrationExpirationDateTime()) .isEqualTo(DateTime.parse("2018-12-06T13:55:01.002Z")); assertInStdout("Successfully unrenewed all domains."); } @@ -149,8 +149,8 @@ void test_unrenewDomain_savesDependentEntitiesCorrectly() throws Exception { .build())); // Check that fields on domain were updated correctly. - assertThat(domain.getRegistrationExpirationTime()).isEqualTo(newExpirationTime); - assertThat(domain.getLastEppUpdateTime()).isEqualTo(unrenewTime); + assertThat(domain.getRegistrationExpirationDateTime()).isEqualTo(newExpirationTime); + assertThat(domain.getLastEppUpdateDateTime()).isEqualTo(unrenewTime); assertThat(domain.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar"); } diff --git a/core/src/test/java/google/registry/tools/UpdatePremiumListCommandTest.java b/core/src/test/java/google/registry/tools/UpdatePremiumListCommandTest.java index b76ab2cdad6..c0a46d67f7b 100644 --- a/core/src/test/java/google/registry/tools/UpdatePremiumListCommandTest.java +++ b/core/src/test/java/google/registry/tools/UpdatePremiumListCommandTest.java @@ -60,7 +60,6 @@ void commandPrompt_successStageEntityChange() throws Exception { File tmpFile = tmpDir.resolve(String.format("%s.txt", TLD_TEST)).toFile(); String newPremiumListData = "omg,USD 1234"; Files.asCharSink(tmpFile, UTF_8).write(newPremiumListData); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); command.inputFile = Paths.get(tmpFile.getPath()); command.name = TLD_TEST; assertThat(command.prompt()).contains("Update premium list for prime?"); @@ -69,7 +68,6 @@ void commandPrompt_successStageEntityChange() throws Exception { @Test void commandPrompt_successStageNoChange() throws Exception { File tmpFile = tmpDir.resolve(String.format("%s.txt", TLD_TEST)).toFile(); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); command.inputFile = Paths.get(tmpFile.getPath()); command.name = TLD_TEST; assertThat(command.prompt()) @@ -82,7 +80,6 @@ void commandRun_successUpdateList() throws Exception { String newPremiumListData = "eth,USD 9999"; Files.asCharSink(tmpFile, UTF_8).write(newPremiumListData); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); // data come from @beforeEach of CreateOrUpdatePremiumListCommandTestCase.java command.inputFile = Paths.get(tmpFile.getPath()); runCommandForced("--name=" + TLD_TEST, "--input=" + command.inputFile); @@ -96,7 +93,6 @@ void commandRun_successUpdateList() throws Exception { void commandRun_successNoChange() throws Exception { File tmpFile = tmpDir.resolve(String.format("%s.txt", TLD_TEST)).toFile(); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); command.inputFile = Paths.get(tmpFile.getPath()); runCommandForced("--name=" + TLD_TEST, "--input=" + command.inputFile); @@ -113,7 +109,6 @@ void commandRun_successUpdateList_whenExistingListIsEmpty() throws Exception { String newPremiumListData = "eth,USD 9999"; Files.asCharSink(newPremiumFile, UTF_8).write(newPremiumListData); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); // data come from @beforeEach of CreateOrUpdatePremiumListCommandTestCase.java command.inputFile = Paths.get(newPremiumFile.getPath()); runCommandForced("--name=" + TLD_TEST, "--input=" + command.inputFile); @@ -129,7 +124,6 @@ void commandRun_successUpdateMultiLineList() throws Exception { String premiumTerms = "foo,USD 9000\ndoge,USD 100\nelon,USD 2021"; Files.asCharSink(tmpFile, UTF_8).write(premiumTerms); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); command.inputFile = Paths.get(tmpFile.getPath()); runCommandForced("--name=" + TLD_TEST, "--input=" + command.inputFile); @@ -146,7 +140,6 @@ void commandPrompt_failureUpdateEmptyList() throws Exception { Path tmpPath = tmpDir.resolve(String.format("%s.txt", TLD_TEST)); Files.write(new byte[0], tmpPath.toFile()); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); command.inputFile = tmpPath; command.name = TLD_TEST; IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, command::prompt); @@ -156,7 +149,6 @@ void commandPrompt_failureUpdateEmptyList() throws Exception { @Test void commandPrompt_failureNoPreviousVersion() { registry = createTld("random", null, null); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); command.name = "random"; IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, command::prompt); assertThat(thrown) @@ -166,13 +158,11 @@ void commandPrompt_failureNoPreviousVersion() { @Test void commandPrompt_failureNoInputFile() { - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); assertThrows(NullPointerException.class, command::prompt); } @Test void commandPrompt_failureTldFromNameDoesNotExist() { - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); command.name = "random2"; IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, command::prompt); assertThat(thrown) @@ -182,7 +172,6 @@ void commandPrompt_failureTldFromNameDoesNotExist() { @Test void commandPrompt_failureTldFromInputFileDoesNotExist() { - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); // using tld extracted from file name but this tld is not part of the registry command.inputFile = Paths.get(tmpDir.resolve("random3.txt").toFile().getPath()); IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, command::prompt); @@ -197,7 +186,6 @@ void commandDryRun_noChangesMade() throws Exception { String newPremiumListData = "eth,USD 9999"; Files.asCharSink(tmpFile, UTF_8).write(newPremiumListData); - UpdatePremiumListCommand command = new UpdatePremiumListCommand(); command.inputFile = Paths.get(tmpFile.getPath()); runCommandForced("--name=" + TLD_TEST, "--input=" + command.inputFile, "--dry_run"); diff --git a/core/src/test/java/google/registry/tools/UpdateReservedListCommandTest.java b/core/src/test/java/google/registry/tools/UpdateReservedListCommandTest.java index 52d3f5f12cd..8d7f4943ea0 100644 --- a/core/src/test/java/google/registry/tools/UpdateReservedListCommandTest.java +++ b/core/src/test/java/google/registry/tools/UpdateReservedListCommandTest.java @@ -98,7 +98,6 @@ void testSuccess_noChanges() throws Exception { Files.asCharSink(reservedTermsFile, UTF_8).write(reservedTermsCsv); reservedTermsPath = reservedTermsFile.getPath(); // create a command instance and assign its input - UpdateReservedListCommand command = new UpdateReservedListCommand(); command.input = Paths.get(reservedTermsPath); // run again with terms from example_reserved_terms.csv command.init(); @@ -110,7 +109,6 @@ void testSuccess_noChanges() throws Exception { void testSuccess_withChanges() throws Exception { // changes come from example_reserved_terms.csv, which are populated in @BeforeEach of // CreateOrUpdateReservedListCommandTestCases.java - UpdateReservedListCommand command = new UpdateReservedListCommand(); command.input = Paths.get(reservedTermsPath); command.init(); diff --git a/core/src/test/java/google/registry/ui/server/console/domains/ConsoleBulkDomainActionTest.java b/core/src/test/java/google/registry/ui/server/console/domains/ConsoleBulkDomainActionTest.java index 7f5338f5e45..da0162a688e 100644 --- a/core/src/test/java/google/registry/ui/server/console/domains/ConsoleBulkDomainActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/domains/ConsoleBulkDomainActionTest.java @@ -19,6 +19,7 @@ import static google.registry.testing.DatabaseHelper.loadSingleton; import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources; import static google.registry.testing.DatabaseHelper.persistResource; +import static google.registry.util.DateTimeUtils.plusDays; import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN; import static jakarta.servlet.http.HttpServletResponse.SC_OK; @@ -92,7 +93,7 @@ void testSuccess_delete() { {"example.tld":{"message":"Command completed successfully; action pending",\ "responseCode":1001}}\ """); - assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35)); + assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(plusDays(clock.now(), 35)); ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get(); assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_DELETE); assertThat(history.getDescription()).hasValue("example.tld"); @@ -162,7 +163,7 @@ void testHalfSuccess_halfNonexistent() throws Exception { "nonexistent.tld":{"message":"The domain with given ID (nonexistent.tld) doesn\\u0027t exist.",\ "responseCode":2303}}\ """); - assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35)); + assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(plusDays(clock.now(), 35)); ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get(); assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_DELETE); assertThat(history.getDescription()).hasValue("example.tld"); diff --git a/networking/src/main/java/google/registry/networking/module/CertificateSupplierModule.java b/networking/src/main/java/google/registry/networking/module/CertificateSupplierModule.java index d0b24f1ebed..ef4fb9e13c2 100644 --- a/networking/src/main/java/google/registry/networking/module/CertificateSupplierModule.java +++ b/networking/src/main/java/google/registry/networking/module/CertificateSupplierModule.java @@ -25,6 +25,7 @@ import dagger.Lazy; import dagger.Module; import dagger.Provides; +import google.registry.util.Clock; import google.registry.util.SelfSignedCaCertificate; import jakarta.inject.Named; import jakarta.inject.Provider; @@ -156,9 +157,9 @@ static Supplier> provideCertificatesSupplier( @Singleton @Provides - static SelfSignedCaCertificate provideSelfSignedCertificate() { + static SelfSignedCaCertificate provideSelfSignedCertificate(Clock clock) { try { - return SelfSignedCaCertificate.create(); + return SelfSignedCaCertificate.create(clock); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/networking/src/test/java/google/registry/networking/handler/SslClientInitializerTest.java b/networking/src/test/java/google/registry/networking/handler/SslClientInitializerTest.java index 7db756da6d1..928d3ed5f7a 100644 --- a/networking/src/test/java/google/registry/networking/handler/SslClientInitializerTest.java +++ b/networking/src/test/java/google/registry/networking/handler/SslClientInitializerTest.java @@ -22,6 +22,7 @@ import static org.joda.time.DateTimeZone.UTC; import com.google.common.collect.ImmutableList; +import google.registry.testing.FakeClock; import google.registry.util.SelfSignedCaCertificate; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; @@ -173,7 +174,7 @@ void testSuccess_nullPort(SslProvider sslProvider) { @MethodSource("provideTestCombinations") void testFailure_defaultTrustManager_rejectSelfSignedCert(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("DEFAULT_TRUST_MANAGER_REJECT_SELF_SIGNED_CERT_" + sslProvider); nettyExtension.setUpServer(localAddress, getServerHandler(false, ssc.key(), ssc.cert())); @@ -204,7 +205,7 @@ void testSuccess_customTrustManager_acceptCertSignedByTrustedCa(SslProvider sslP KeyPair keyPair = getKeyPair(); // Generate a self-signed certificate, and use it to sign the key pair. - SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(new FakeClock()); X509Certificate cert = signKeyPair(ssc, keyPair, SSL_HOST); // Set up the server to use the signed cert and private key to perform handshake; @@ -239,7 +240,7 @@ void testFailure_customTrustManager_serverCertExpired(SslProvider sslProvider) t KeyPair keyPair = getKeyPair(); // Generate a self-signed certificate, and use it to sign the key pair. - SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(new FakeClock()); X509Certificate cert = signKeyPair( ssc, keyPair, SSL_HOST, DateTime.now(UTC).minusDays(2), DateTime.now(UTC).minusDays(1)); @@ -276,7 +277,7 @@ void testFailure_customTrustManager_serverCertNotYetValid(SslProvider sslProvide KeyPair keyPair = getKeyPair(); // Generate a self-signed certificate, and use it to sign the key pair. - SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(new FakeClock()); X509Certificate cert = signKeyPair( ssc, keyPair, SSL_HOST, DateTime.now(UTC).plusDays(1), DateTime.now(UTC).plusDays(2)); @@ -310,8 +311,8 @@ void testSuccess_customTrustManager_acceptSelfSignedCert_clientCertRequired( new LocalAddress( "CUSTOM_TRUST_MANAGER_ACCEPT_SELF_SIGNED_CERT_CLIENT_CERT_REQUIRED_" + sslProvider); - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); - SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); + SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create(new FakeClock()); // Set up the server to require client certificate. nettyExtension.setUpServer( @@ -352,7 +353,7 @@ void testFailure_customTrustManager_wrongHostnameInCertificate(SslProvider sslPr KeyPair keyPair = getKeyPair(); // Generate a self-signed certificate, and use it to sign the key pair. - SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(new FakeClock()); X509Certificate cert = signKeyPair(ssc, keyPair, "wrong.com"); // Set up the server to use the signed cert and private key to perform handshake; diff --git a/networking/src/test/java/google/registry/networking/handler/SslServerInitializerTest.java b/networking/src/test/java/google/registry/networking/handler/SslServerInitializerTest.java index d1736bfa848..d7646e00b5b 100644 --- a/networking/src/test/java/google/registry/networking/handler/SslServerInitializerTest.java +++ b/networking/src/test/java/google/registry/networking/handler/SslServerInitializerTest.java @@ -24,6 +24,7 @@ import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; +import google.registry.testing.FakeClock; import google.registry.util.SelfSignedCaCertificate; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelInitializer; @@ -148,7 +149,7 @@ private ChannelHandler getClientHandler( @ParameterizedTest @MethodSource("provideTestCombinations") void testSuccess_swappedInitializerWithSslHandler(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); SslServerInitializer sslServerInitializer = new SslServerInitializer<>( true, @@ -169,13 +170,13 @@ void testSuccess_swappedInitializerWithSslHandler(SslProvider sslProvider) throw @ParameterizedTest @MethodSource("provideTestCombinations") void testSuccess_trustAnyClientCert(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("TRUST_ANY_CLIENT_CERT_" + sslProvider); nettyExtension.setUpServer( localAddress, getServerHandler(true, false, sslProvider, serverSsc.key(), serverSsc.cert())); - SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create(new FakeClock()); nettyExtension.setUpClient( localAddress, getClientHandler(sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert())); @@ -193,7 +194,7 @@ void testSuccess_trustAnyClientCert(SslProvider sslProvider) throws Exception { @ParameterizedTest @MethodSource("provideTestCombinations") void testFailure_cipherNotAccepted(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("CIPHER_NOT_ACCEPTED_" + sslProvider); nettyExtension.setUpServer( @@ -220,7 +221,7 @@ void testFailure_cipherNotAccepted(SslProvider sslProvider) throws Exception { @ParameterizedTest @MethodSource("provideTestCombinations") void testSuccess_someCiphersNotAccepted(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("SOME_CIPHERS_NOT_ACCEPTED_" + sslProvider); nettyExtension.setUpServer( @@ -258,7 +259,7 @@ void testSuccess_someCiphersNotAccepted(SslProvider sslProvider) throws Exceptio @ParameterizedTest @MethodSource("provideTestCombinations") void testFailure_protocolNotAccepted(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("PROTOCOL_NOT_ACCEPTED_" + sslProvider); nettyExtension.setUpServer( @@ -288,7 +289,7 @@ void testFailure_protocolNotAccepted(SslProvider sslProvider) throws Exception { @ParameterizedTest @MethodSource("provideTestCombinations") void testFailure_clientCertExpired(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("CLIENT_CERT_EXPIRED_" + sslProvider); nettyExtension.setUpServer( @@ -309,7 +310,7 @@ void testFailure_clientCertExpired(SslProvider sslProvider) throws Exception { @ParameterizedTest @MethodSource("provideTestCombinations") void testFailure_clientCertNotYetValid(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("CLIENT_CERT_EXPIRED_" + sslProvider); nettyExtension.setUpServer( @@ -330,7 +331,7 @@ void testFailure_clientCertNotYetValid(SslProvider sslProvider) throws Exception @ParameterizedTest @MethodSource("provideTestCombinations") void testSuccess_doesNotRequireClientCert(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("DOES_NOT_REQUIRE_CLIENT_CERT_" + sslProvider); nettyExtension.setUpServer( @@ -353,7 +354,7 @@ void testSuccess_doesNotRequireClientCert(SslProvider sslProvider) throws Except @MethodSource("provideTestCombinations") void testSuccess_CertSignedByOtherCa(SslProvider sslProvider) throws Exception { // The self-signed cert of the CA. - SelfSignedCaCertificate caSsc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate caSsc = SelfSignedCaCertificate.create(new FakeClock()); KeyPair keyPair = getKeyPair(); X509Certificate serverCert = signKeyPair(caSsc, keyPair, SSL_HOST); LocalAddress localAddress = new LocalAddress("CERT_SIGNED_BY_OTHER_CA_" + sslProvider); @@ -368,7 +369,7 @@ void testSuccess_CertSignedByOtherCa(SslProvider sslProvider) throws Exception { // Serving both the server cert, and the CA cert serverCert, caSsc.cert())); - SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create(new FakeClock()); nettyExtension.setUpClient( localAddress, getClientHandler( @@ -392,7 +393,7 @@ void testSuccess_CertSignedByOtherCa(SslProvider sslProvider) throws Exception { @ParameterizedTest @MethodSource("provideTestCombinations") void testFailure_requireClientCertificate(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST); + SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST, new FakeClock()); LocalAddress localAddress = new LocalAddress("REQUIRE_CLIENT_CERT_" + sslProvider); nettyExtension.setUpServer( @@ -417,13 +418,14 @@ void testFailure_requireClientCertificate(SslProvider sslProvider) throws Except @ParameterizedTest @MethodSource("provideTestCombinations") void testFailure_wrongHostnameInCertificate(SslProvider sslProvider) throws Exception { - SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create("wrong.com"); + SelfSignedCaCertificate serverSsc = + SelfSignedCaCertificate.create("wrong.com", new FakeClock()); LocalAddress localAddress = new LocalAddress("WRONG_HOSTNAME_" + sslProvider); nettyExtension.setUpServer( localAddress, getServerHandler(true, false, sslProvider, serverSsc.key(), serverSsc.cert())); - SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create(); + SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create(new FakeClock()); nettyExtension.setUpClient( localAddress, getClientHandler(sslProvider, serverSsc.cert(), clientSsc.key(), clientSsc.cert())); diff --git a/networking/src/test/java/google/registry/networking/module/CertificateSupplierModuleTest.java b/networking/src/test/java/google/registry/networking/module/CertificateSupplierModuleTest.java index 70ffbfe3ecb..13acae86ac3 100644 --- a/networking/src/test/java/google/registry/networking/module/CertificateSupplierModuleTest.java +++ b/networking/src/test/java/google/registry/networking/module/CertificateSupplierModuleTest.java @@ -26,6 +26,8 @@ import dagger.Module; import dagger.Provides; import google.registry.networking.module.CertificateSupplierModule.Mode; +import google.registry.testing.FakeClock; +import google.registry.util.Clock; import google.registry.util.SelfSignedCaCertificate; import jakarta.inject.Named; import jakarta.inject.Singleton; @@ -59,7 +61,7 @@ private static TestComponent createComponentForPem(Object... objects) throws Exc @BeforeEach void beforeEach() throws Exception { - ssc = SelfSignedCaCertificate.create(); + ssc = SelfSignedCaCertificate.create(new FakeClock()); KeyPair keyPair = getKeyPair(); key = keyPair.getPrivate(); cert = signKeyPair(ssc, keyPair, "example.tld"); @@ -147,6 +149,11 @@ Duration provideCachingDuration() { // Make the supplier always return the save value for test to save time. return Duration.ofDays(1); } + + @Provides + Clock provideClock() { + return new FakeClock(); + } } /** diff --git a/proxy/src/test/java/google/registry/proxy/EppProtocolModuleTest.java b/proxy/src/test/java/google/registry/proxy/EppProtocolModuleTest.java index f6fb6f53460..fa71772ec4a 100644 --- a/proxy/src/test/java/google/registry/proxy/EppProtocolModuleTest.java +++ b/proxy/src/test/java/google/registry/proxy/EppProtocolModuleTest.java @@ -24,6 +24,7 @@ import com.google.common.base.Throwables; import google.registry.proxy.handler.HttpsRelayServiceHandler.NonOkHttpResponseException; +import google.registry.testing.FakeClock; import google.registry.util.SelfSignedCaCertificate; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -122,7 +123,7 @@ private static FullHttpResponse makeEppHttpResponse( @Override void beforeEach() throws Exception { testComponent = makeTestComponent(); - certificate = SelfSignedCaCertificate.create().cert(); + certificate = SelfSignedCaCertificate.create(new FakeClock()).cert(); initializeChannel( ch -> { ch.attr(REMOTE_ADDRESS_KEY).set(CLIENT_ADDRESS); diff --git a/proxy/src/test/java/google/registry/proxy/handler/EppServiceHandlerTest.java b/proxy/src/test/java/google/registry/proxy/handler/EppServiceHandlerTest.java index cc4c4578d1e..8ccab79f1ae 100644 --- a/proxy/src/test/java/google/registry/proxy/handler/EppServiceHandlerTest.java +++ b/proxy/src/test/java/google/registry/proxy/handler/EppServiceHandlerTest.java @@ -32,6 +32,7 @@ import google.registry.proxy.TestUtils; import google.registry.proxy.handler.HttpsRelayServiceHandler.NonOkHttpResponseException; import google.registry.proxy.metric.FrontendMetrics; +import google.registry.testing.FakeClock; import google.registry.util.ProxyHttpHeaders; import google.registry.util.SelfSignedCaCertificate; import io.netty.buffer.ByteBuf; @@ -114,7 +115,7 @@ private FullHttpRequest makeEppHttpRequest(String content, Cookie... cookies) th @BeforeEach void beforeEach() throws Exception { - clientCertificate = SelfSignedCaCertificate.create().cert(); + clientCertificate = SelfSignedCaCertificate.create(new FakeClock()).cert(); channel = setUpNewChannel(eppServiceHandler); } @@ -171,7 +172,7 @@ void testSuccess_connectionMetrics_twoConnections_differentClients() throws Exce new EppServiceHandler( RELAY_HOST, RELAY_PATH, false, () -> ID_TOKEN, HELLO.getBytes(UTF_8), metrics); EmbeddedChannel channel2 = setUpNewChannel(eppServiceHandler2); - X509Certificate clientCertificate2 = SelfSignedCaCertificate.create().cert(); + X509Certificate clientCertificate2 = SelfSignedCaCertificate.create(new FakeClock()).cert(); setHandshakeSuccess(channel2, clientCertificate2); String certHash2 = getCertificateHash(clientCertificate2); diff --git a/util/src/main/java/google/registry/util/PosixTarHeader.java b/util/src/main/java/google/registry/util/PosixTarHeader.java index 4d9b40550d2..5c68086c253 100644 --- a/util/src/main/java/google/registry/util/PosixTarHeader.java +++ b/util/src/main/java/google/registry/util/PosixTarHeader.java @@ -324,12 +324,12 @@ public static class Builder { private final byte[] header = new byte[HEADER_LENGTH]; private boolean hasName = false; private boolean hasSize = false; + private boolean hasMtime = false; public Builder() { setMode(DEFAULT_MODE); setUid(DEFAULT_UID); setGid(DEFAULT_GID); - setMtime(DateTime.now(UTC)); setType(DEFAULT_TYPE); setMagic(); setVersion(); @@ -418,6 +418,7 @@ public Builder setSize(long size) { public Builder setMtime(DateTime mtime) { checkNotNull(mtime, "mtime"); setField("mtime", 136, 12, String.format("%011o", mtime.getMillis() / MILLIS_PER_SECOND)); + hasMtime = true; return this; } @@ -483,8 +484,10 @@ private void setVersion() { public PosixTarHeader build() { checkState(hasName, "name not set"); checkState(hasSize, "size not set"); + checkState(hasMtime, "mtime not set"); hasName = false; hasSize = false; + hasMtime = false; setChksum(); // Calculate the checksum last. return new PosixTarHeader(header.clone()); } diff --git a/util/src/main/java/google/registry/util/SelfSignedCaCertificate.java b/util/src/main/java/google/registry/util/SelfSignedCaCertificate.java index 189c77cf549..4f58929ce0f 100644 --- a/util/src/main/java/google/registry/util/SelfSignedCaCertificate.java +++ b/util/src/main/java/google/registry/util/SelfSignedCaCertificate.java @@ -15,7 +15,6 @@ package google.registry.util; import static com.google.common.base.Preconditions.checkArgument; -import static org.joda.time.DateTimeZone.UTC; import com.google.common.collect.ImmutableMap; import java.math.BigInteger; @@ -42,8 +41,6 @@ public class SelfSignedCaCertificate { private static final String DEFAULT_ISSUER_FQDN = "registry-test"; - private static final DateTime DEFAULT_NOT_BEFORE = DateTime.now(UTC).minusHours(1); - private static final DateTime DEFAULT_NOT_AFTER = DateTime.now(UTC).plusDays(1); private static final Random RANDOM = new Random(); private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider(); @@ -68,13 +65,16 @@ public X509Certificate cert() { return cert; } - public static SelfSignedCaCertificate create() throws Exception { + public static SelfSignedCaCertificate create(Clock clock) throws Exception { return create( - keyGen.generateKeyPair(), DEFAULT_ISSUER_FQDN, DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER); + keyGen.generateKeyPair(), + DEFAULT_ISSUER_FQDN, + clock.nowUtc().minusHours(1), + clock.nowUtc().plusDays(1)); } - public static SelfSignedCaCertificate create(String fqdn) throws Exception { - return create(fqdn, DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER); + public static SelfSignedCaCertificate create(String fqdn, Clock clock) throws Exception { + return create(fqdn, clock.nowUtc().minusHours(1), clock.nowUtc().plusDays(1)); } public static SelfSignedCaCertificate create(String fqdn, DateTime from, DateTime to) diff --git a/util/src/test/java/google/registry/util/DateTimeUtilsTest.java b/util/src/test/java/google/registry/util/DateTimeUtilsTest.java index 4dc92aa1f14..eaacd8308af 100644 --- a/util/src/test/java/google/registry/util/DateTimeUtilsTest.java +++ b/util/src/test/java/google/registry/util/DateTimeUtilsTest.java @@ -15,7 +15,9 @@ package google.registry.util; import static com.google.common.truth.Truth.assertThat; +import static google.registry.util.DateTimeUtils.END_INSTANT; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.START_INSTANT; import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.earliestOf; import static google.registry.util.DateTimeUtils.isAtOrAfter; @@ -23,12 +25,15 @@ import static google.registry.util.DateTimeUtils.latestOf; import static google.registry.util.DateTimeUtils.leapSafeAddYears; import static google.registry.util.DateTimeUtils.leapSafeSubtractYears; +import static google.registry.util.DateTimeUtils.toDateTime; +import static google.registry.util.DateTimeUtils.toInstant; import static google.registry.util.DateTimeUtils.toLocalDate; import static google.registry.util.DateTimeUtils.toSqlDate; import static org.junit.jupiter.api.Assertions.assertThrows; import com.google.common.collect.ImmutableList; import java.sql.Date; +import java.time.Instant; import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.junit.jupiter.api.Test; @@ -42,7 +47,7 @@ class DateTimeUtilsTest { @Test void testSuccess_earliestOf() { assertThat(earliestOf(START_OF_TIME, END_OF_TIME)).isEqualTo(START_OF_TIME); - assertThat(earliestOf(sampleDates)).isEqualTo(START_OF_TIME); + assertThat(DateTimeUtils.earliestDateTimeOf(sampleDates)).isEqualTo(START_OF_TIME); } @Test @@ -72,6 +77,12 @@ void testSuccess_leapSafeAddYears() { assertThat(leapSafeAddYears(startDate, 4)).isEqualTo(DateTime.parse("2016-02-28T00:00:00Z")); } + @Test + void test_leapSafeAddYears_worksWithInstants() { + Instant startDate = Instant.parse("2012-02-29T00:00:00Z"); + assertThat(leapSafeAddYears(startDate, 4)).isEqualTo(Instant.parse("2016-02-28T00:00:00Z")); + } + @Test void testSuccess_leapSafeSubtractYears() { DateTime startDate = DateTime.parse("2012-02-29T00:00:00Z"); @@ -80,6 +91,13 @@ void testSuccess_leapSafeSubtractYears() { .isEqualTo(DateTime.parse("2008-02-28T00:00:00Z")); } + @Test + void test_leapSafeSubtractYears_worksWithInstants() { + Instant startDate = Instant.parse("2012-02-29T00:00:00Z"); + assertThat(leapSafeSubtractYears(startDate, 4)) + .isEqualTo(Instant.parse("2008-02-28T00:00:00Z")); + } + @Test void testSuccess_leapSafeSubtractYears_zeroYears() { DateTime leapDay = DateTime.parse("2012-02-29T00:00:00Z"); @@ -93,7 +111,7 @@ void testFailure_earliestOfEmpty() { @Test void testFailure_latestOfEmpty() { - assertThrows(IllegalArgumentException.class, () -> earliestOf(ImmutableList.of())); + assertThrows(IllegalArgumentException.class, () -> latestOf(ImmutableList.of())); } @Test @@ -107,4 +125,32 @@ void testSuccess_toLocalDate() { Date date = Date.valueOf("2020-02-29"); assertThat(toLocalDate(date)).isEqualTo(LocalDate.parse("2020-02-29")); } + + @Test + void test_startOfTimeConstants_areTheSame() { + assertThat(toInstant(START_OF_TIME)).isEqualTo(START_INSTANT); + assertThat(toDateTime(START_INSTANT)).isEqualTo(START_OF_TIME); + assertThat(toInstant(toDateTime(START_INSTANT))).isEqualTo(START_INSTANT); + assertThat(toDateTime(toInstant(START_OF_TIME))).isEqualTo(START_OF_TIME); + } + + @Test + void test_endOfTimeConstants_areTheSame() { + assertThat(toInstant(END_OF_TIME)).isEqualTo(END_INSTANT); + assertThat(toDateTime(END_INSTANT)).isEqualTo(END_OF_TIME); + assertThat(toInstant(toDateTime(END_INSTANT))).isEqualTo(END_INSTANT); + assertThat(toDateTime(toInstant(END_OF_TIME))).isEqualTo(END_OF_TIME); + } + + @Test + void test_instantConversionMethods_workCorrectly() { + assertThat(toInstant(DateTime.parse("2024-03-27T10:15:30.105Z"))) + .isEqualTo(Instant.parse("2024-03-27T10:15:30.105Z")); + assertThat(toDateTime(Instant.parse("2024-03-27T10:15:30.105Z"))) + .isEqualTo(DateTime.parse("2024-03-27T10:15:30.105Z")); + assertThat(toInstant(toDateTime(Instant.parse("2024-03-27T10:15:30.105Z")))) + .isEqualTo(Instant.parse("2024-03-27T10:15:30.105Z")); + assertThat(toDateTime(toInstant(DateTime.parse("2024-03-27T10:15:30.105Z")))) + .isEqualTo(DateTime.parse("2024-03-27T10:15:30.105Z")); + } } diff --git a/util/src/test/java/google/registry/util/PosixTarHeaderTest.java b/util/src/test/java/google/registry/util/PosixTarHeaderTest.java index da8a1a70c0f..1b0d41bc902 100644 --- a/util/src/test/java/google/registry/util/PosixTarHeaderTest.java +++ b/util/src/test/java/google/registry/util/PosixTarHeaderTest.java @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.zip.GZIPInputStream; import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; import org.joda.time.format.ISODateTimeFormat; import org.junit.jupiter.api.Test; @@ -199,7 +200,11 @@ void testLoad() { @Test void testBadChecksum() { PosixTarHeader header = - new PosixTarHeader.Builder().setName("(◕‿◕).txt").setSize(31337).build(); + new PosixTarHeader.Builder() + .setName("(◕‿◕).txt") + .setSize(31337) + .setMtime(DateTime.now(DateTimeZone.UTC)) + .build(); byte[] bytes = header.getBytes(); bytes[150] = '0'; bytes[151] = '0'; @@ -234,6 +239,7 @@ void testHashEquals() { new PosixTarHeader.Builder() .setName("(•︵•).txt") // Awwwww! It looks so sad... .setSize(123) + .setMtime(DateTime.now(DateTimeZone.UTC)) .build()) .testEquals(); }