1
0
mirror of https://github.com/google/nomulus synced 2026-06-09 16:33:02 +00:00

Begin migration of joda DateTime to java.time.Instant (#2992)

java.time has been around since Java 8 and was based on joda DateTime, so this
is an overdue migration.  We're migrating specifically to Instant in most places
rather than ZonedDateTime because we were always using DateTimes in UTC to
reference a specific instant, which is exactly what Instants are
for. ZonedDateTime set to UTC may still be useful in some places that are heavy
on date math (especially in tests).

There is a lot more work to be done after this, but I wanted to put together a
manual PR showing my overall approach for how to do the migration that I can
then hopefully follow along with AI to continue making these changes throughout
the codebase. The basic approach is to migrate a small number of methods at a
time, marking the old methods as @Deprecated when possible (not always possible
because of @InlineMe restrictions). This PR doesn't yet migrate any DateTime
fields in the model classes, so that's the one remaining type of refactor to
figure out after this. We won't be changing how any of the data is actually
stored in the database.

BUG= http://b/496985355
This commit is contained in:
Ben McIlwain
2026-03-31 16:30:29 -04:00
committed by GitHub
parent aedfdd47f1
commit 60e84e72d7
66 changed files with 530 additions and 213 deletions
@@ -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 @@ import org.joda.time.DateTime;
public interface Clock extends Serializable {
/** Returns current time in UTC timezone. */
@Deprecated
DateTime nowUtc();
/** Returns current Instant (which is always in UTC). */
Instant now();
}
@@ -20,6 +20,9 @@ import com.google.common.collect.Iterables;
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 @@ import org.joda.time.LocalDate;
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 (which is defined 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.
*
* <p>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<DateTime> dates) {
public static DateTime earliestDateTimeOf(Iterable<DateTime> dates) {
checkArgument(!Iterables.isEmpty(dates));
return Ordering.<DateTime>natural().min(dates);
}
/** Returns the earliest element in a {@link Instant} iterable. */
public static Instant earliestOf(Iterable<Instant> instants) {
checkArgument(!Iterables.isEmpty(instants));
return Ordering.<Instant>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 abstract class DateTimeUtils {
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 java.time.ZonedDateTime#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 java.time.ZonedDateTime#minusYears} to ensure that we never end up on February 29.
*/
public static Instant leapSafeSubtractYears(Instant now, int 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 abstract class DateTimeUtils {
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();
}
}
@@ -17,6 +17,7 @@ package google.registry.util;
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,9 @@ public class SystemClock implements Clock {
public DateTime nowUtc() {
return DateTime.now(UTC);
}
@Override
public Instant now() {
return Instant.now();
}
}
@@ -19,6 +19,7 @@ import static org.joda.time.DateTimeZone.UTC;
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 final class FakeClock implements Clock {
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.
@@ -17,6 +17,7 @@ package google.registry.batch;
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.Parameter;
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 @@ public class BulkDomainTransferAction implements Runnable {
private boolean shouldSkipDomain(String domainName) {
Optional<Domain> 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 @@ public class BulkDomainTransferAction implements Runnable {
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;
@@ -18,6 +18,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
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 @@ public class DeleteExpiredDomainsAction implements Runnable {
"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());
@@ -188,7 +188,7 @@ public class RelockDomainAction implements Runnable {
"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(
@@ -24,6 +24,7 @@ import static google.registry.util.CollectionUtils.union;
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 @@ public class ExpandBillingRecurrencesPipeline implements Serializable {
// during ARGP).
//
// See: DomainFlowUtils#createCancellingRecords
domain.getDeletionTime().isBefore(billingTime)
domain.getDeletionTime().isBefore(toInstant(billingTime))
? ImmutableSet.of()
: ImmutableSet.of(
DomainTransactionRecord.create(
@@ -16,6 +16,7 @@ package google.registry.flows;
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.eppcommon.StatusValue;
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 final class ResourceFlowUtils {
public static <R extends EppResource & ForeignKeyedEppResource> R loadAndVerifyExistence(
Class<R> clazz, String targetId, DateTime now) throws ResourceDoesNotExistException {
return loadAndVerifyExistence(clazz, targetId, toInstant(now));
}
public static <R extends EppResource & ForeignKeyedEppResource> R loadAndVerifyExistence(
Class<R> clazz, String targetId, Instant now) throws ResourceDoesNotExistException {
return verifyExistence(clazz, targetId, ForeignKeyUtils.loadResource(clazz, targetId, now));
}
@@ -197,8 +204,8 @@ public final class ResourceFlowUtils {
*
* @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.
@@ -236,7 +236,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
}
// 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 final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
flowCustomLogic.beforeResponse(
BeforeResponseParameters.newBuilder()
.setResultCode(
newDomain.getDeletionTime().isAfter(now)
newDomain.getDeletionDateTime().isAfter(now)
? SUCCESS_WITH_ACTION_PENDING
: SUCCESS)
.setResponseExtensions(
@@ -503,7 +503,7 @@ public class DomainFlowUtils {
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setTargetId(domain.getDomainName())
.setRegistrarId(domain.getCurrentSponsorRegistrarId())
.setEventTime(domain.getRegistrationExpirationTime());
.setEventTime(domain.getRegistrationExpirationDateTime());
}
/**
@@ -514,7 +514,7 @@ public class DomainFlowUtils {
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 @@ public class DomainFlowUtils {
// 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 -> {
@@ -122,8 +122,8 @@ public final class DomainInfoFlow implements MutatingFlow {
.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
@@ -191,7 +191,7 @@ public final class DomainRenewFlow implements MutatingFlow {
existingDomain = maybeApplyBulkPricingRemovalToken(existingDomain, allocationToken);
DateTime newExpirationTime =
leapSafeAddYears(existingDomain.getRegistrationExpirationTime(), years); // Uncapped
leapSafeAddYears(existingDomain.getRegistrationExpirationDateTime(), years); // Uncapped
validateRegistrationPeriod(now, newExpirationTime);
Optional<FeeRenewCommandExtension> feeRenew =
eppInput.getSingleExtension(FeeRenewCommandExtension.class);
@@ -328,8 +328,9 @@ public final class DomainRenewFlow implements MutatingFlow {
// 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();
}
}
@@ -138,7 +138,7 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
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<FeeUpdateCommandExtension> feeUpdate =
@@ -149,7 +149,7 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
ImmutableSet.Builder<ImmutableObject> 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) {
@@ -33,6 +33,8 @@ import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_
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 final class DomainTransferApproveFlow implements MutatingFlow {
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 final class DomainTransferApproveFlow implements MutatingFlow {
// 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();
}
@@ -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 final class DomainTransferQueryFlow implements TransactionalFlow {
}
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))
@@ -32,6 +32,7 @@ import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_
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.reporting.IcannReportingTypes.ActivityReportField;
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 final class DomainTransferRejectFlow implements MutatingFlow {
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 final class DomainTransferRejectFlow implements MutatingFlow {
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 =
@@ -35,6 +35,8 @@ import static google.registry.flows.domain.DomainTransferUtils.createTransferSer
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.DomainTransferData.TransferServerApproveEn
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 final class DomainTransferRequestFlow implements MutatingFlow {
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<TransferServerApproveEntity> serverApproveEntities =
createTransferServerApproveEntities(
@@ -287,7 +292,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
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 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
}
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<FeeTransformResponseExtension> createResponseExtensions(
@@ -184,7 +184,7 @@ public final class DomainTransferUtils {
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 final class DomainTransferUtils {
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 @@ public final class DomainTransferUtils {
.setDomainName(targetId)
.setGainingRegistrarId(transferData.getGainingRegistrarId())
.setLosingRegistrarId(transferData.getLosingRegistrarId())
.setPendingTransferExpirationTime(transferData.getPendingTransferExpirationTime())
.setPendingTransferExpirationTime(transferData.getPendingTransferExpirationDateTime())
.setTransferRequestTime(transferData.getTransferRequestTime())
.setTransferStatus(transferData.getTransferStatus())
.setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime)
@@ -281,7 +281,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
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();
@@ -99,7 +99,7 @@ public final class HostInfoFlow implements TransactionalFlow {
.setCreationRegistrarId(host.getCreationRegistrarId())
.setCreationTime(host.getCreationTime())
.setLastEppUpdateRegistrarId(host.getLastEppUpdateRegistrarId())
.setLastEppUpdateTime(host.getLastEppUpdateTime())
.setLastEppUpdateTime(host.getLastEppUpdateDateTime())
.build())
.build();
}
@@ -25,6 +25,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
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.Enumerated;
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 abstract class EppResource extends UpdateAutoTimestampEntity implements B
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 abstract class EppResource extends UpdateAutoTimestampEntity implements B
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();
@@ -34,6 +34,7 @@ import google.registry.model.transfer.DomainTransferData;
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 final class EppResourceUtils {
* 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 final class EppResourceUtils {
builder
.removeStatusValue(StatusValue.PENDING_TRANSFER)
.setTransferData(transferDataBuilder.build())
.setLastTransferTime(transferData.getPendingTransferExpirationTime())
.setLastTransferTime(transferData.getPendingTransferExpirationDateTime())
.setPersistedCurrentSponsorRegistrarId(transferData.getGainingRegistrarId());
}
@@ -120,10 +121,10 @@ public final class EppResourceUtils {
* </ul>
*/
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);
@@ -35,6 +35,7 @@ import google.registry.persistence.VKey;
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 final class ForeignKeyUtils {
* <p>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 <E extends EppResource> Optional<E> loadResource(
Class<E> clazz, String foreignKey, DateTime now) {
// Note: no need to project to "now" because loadResources already does
@@ -88,6 +90,19 @@ public final class ForeignKeyUtils {
loadResources(clazz, ImmutableList.of(foreignKey), now).get(foreignKey));
}
/**
* Loads an {@link EppResource} from the database by foreign key.
*
* <p>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 <E extends EppResource> Optional<E> loadResource(
Class<E> 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 final class ForeignKeyUtils {
* or has been soft-deleted.
*/
@SuppressWarnings("unchecked")
@Deprecated
public static <E extends EppResource> ImmutableMap<String, E> loadResources(
Class<E> clazz, Collection<String> 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.
*
* <p>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 <E extends EppResource> ImmutableMap<String, E> loadResources(
Class<E> clazz, Collection<String> 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 final class ForeignKeyUtils {
return (Optional<E>)
foreignKeyToResourceCache
.get(VKey.create(clazz, foreignKey))
.filter(e -> now.isBefore(e.getDeletionTime()))
.filter(e -> now.isBefore(e.getDeletionDateTime()))
.map(e -> e.cloneProjectedAtTime(now));
}
}
@@ -50,11 +50,11 @@ public final class ResourceTransferUtils {
.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();
@@ -104,7 +104,7 @@ public class BillingCancellation extends BillingBase {
.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) {
@@ -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.JoinColumn;
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 class Domain extends DomainBase implements ForeignKeyedEppResource {
@Override
public Domain cloneProjectedAtTime(final DateTime now) {
return cloneDomainProjectedAtTime(this, toInstant(now));
}
@Override
public Domain cloneProjectedAtInstant(final Instant now) {
return cloneDomainProjectedAtTime(this, now);
}
@@ -32,9 +32,14 @@ import static google.registry.util.DateTimeUtils.END_OF_TIME;
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.Enumerated;
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 class DomainBase extends EppResource {
return nullToEmptyImmutableCopy(subordinateHosts);
}
public DateTime getRegistrationExpirationTime() {
@Deprecated
public DateTime getRegistrationExpirationDateTime() {
return registrationExpirationTime;
}
public Instant getRegistrationExpirationTime() {
return toInstant(registrationExpirationTime);
}
public VKey<OneTime> getDeletePollMessage() {
return deletePollMessage;
}
@@ -436,6 +446,11 @@ public class DomainBase extends EppResource {
@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 class DomainBase extends EppResource {
* parallels the logic in {@code DomainTransferApproveFlow} which handles explicit client
* approvals.
*/
static <T extends DomainBase> T cloneDomainProjectedAtTime(T domain, DateTime now) {
static <T extends DomainBase> 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 @@ public class DomainBase extends EppResource {
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 @@ public class DomainBase extends EppResource {
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 @@ public class DomainBase extends EppResource {
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 @@ public class DomainBase extends EppResource {
// 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<DateTime> newLastEppUpdateTime = Optional.empty();
Optional<Instant> 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 @@ public class DomainBase extends EppResource {
// 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 @@ public class DomainBase extends EppResource {
}
/** 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 class DomainBase extends EppResource {
.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())
@@ -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.EnumType;
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 class GracePeriodBase extends ImmutableObject implements UnsafeSerializab
return domainRepoId;
}
public DateTime getExpirationTime() {
@Deprecated
public DateTime getExpirationDateTime() {
return expirationTime;
}
public Instant getExpirationTime() {
return toInstant(expirationTime);
}
public String getRegistrarId() {
return clientId;
}
@@ -33,6 +33,7 @@ import jakarta.persistence.Column;
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 class HostBase extends EppResource {
return this;
}
@Override
public EppResource cloneProjectedAtInstant(Instant now) {
return this;
}
@Override
public Builder<? extends HostBase, ?> asBuilder() {
return new Builder<>(clone(this));
@@ -232,13 +238,13 @@ public class HostBase extends EppResource {
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())
@@ -437,7 +437,7 @@ public abstract class PollMessage extends ImmutableObject
.setTransferStatus(transferResponse.getTransferStatus())
.setTransferRequestTime(transferResponse.getTransferRequestTime())
.setPendingTransferExpirationTime(
transferResponse.getPendingTransferExpirationTime())
transferResponse.getPendingTransferExpirationDateTime())
.setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime)
.build();
}
@@ -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.Enumerated;
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 abstract class BaseTransferObject extends ImmutableObject implements Unsa
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<T extends BaseTransferObject, B extends Builder<?, ?>>
extends GenericBuilder<T, B> {
@@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkState;
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.Column;
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 class DomainTransferData extends BaseTransferObject implements Buildable
}
@Nullable
public DateTime getTransferredRegistrationExpirationTime() {
@Deprecated
public DateTime getTransferredRegistrationExpirationDateTime() {
return transferredRegistrationExpirationTime;
}
@Nullable
public Instant getTransferredRegistrationExpirationTime() {
return toInstant(transferredRegistrationExpirationTime);
}
@Nullable
public VKey<BillingEvent> getServerApproveBillingEvent() {
return serverApproveBillingEvent;
@@ -21,6 +21,7 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap;
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.Array;
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 class JpaTransactionManagerImpl implements JpaTransactionManager {
@Override
public DateTime getTransactionTime() {
return toDateTime(getTxTime());
}
@Override
public Instant getTxTime() {
assertInTransaction();
TransactionInfo txnInfo = transactionInfo.get();
if (txnInfo.transactionTime == null) {
@@ -746,7 +753,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
private static class TransactionInfo {
EntityManager entityManager;
boolean inTransaction = false;
DateTime transactionTime;
Instant transactionTime;
Supplier<Long> idProvider;
// The set of entity objects that have been either persisted (via insert()) or merged (via
@@ -759,7 +766,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
private void start(Clock clock, Supplier<Long> idProvider) {
checkArgumentNotNull(clock);
inTransaction = true;
transactionTime = clock.nowUtc();
transactionTime = clock.now();
this.idProvider = idProvider;
}
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableMap;
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);
@@ -17,6 +17,7 @@ package google.registry.rdap;
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 @@ public abstract class RdapActionBase implements Runnable {
* 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()));
@@ -318,7 +318,7 @@ public class RdapJsonFormatter {
.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
@@ -361,7 +361,7 @@ public class RdapJsonFormatter {
makeStatusValueList(
allStatusValues,
false, // isRedacted
domain.getDeletionTime().isBefore(getRequestTime()));
domain.getDeletionDateTime().isBefore(getRequestTime()));
builder.statusBuilder().addAll(status);
if (status.isEmpty()) {
logger.atWarning().log(
@@ -447,7 +447,7 @@ public class RdapJsonFormatter {
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.
@@ -761,7 +761,9 @@ public class RdapJsonFormatter {
ImmutableList.Builder<Event> 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()) {
@@ -94,13 +94,13 @@ final class DomainToXjcConverter {
// 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 <upDate> 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 <upRr> element that contains the identifier of the
// registrar that last updated the domain name object. This element
@@ -228,8 +228,8 @@ final class DomainToXjcConverter {
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;
}
@@ -70,7 +70,7 @@ final class HostToXjcConverter {
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));
@@ -81,7 +81,7 @@ final class GenerateDnsReportCommand implements Command {
.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 @@ final class GenerateDnsReportCommand implements Command {
Iterable<Host> 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;
}
@@ -81,7 +81,7 @@ final class RenewDomainCommand extends MutatingEppToolCommand {
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) {
@@ -163,7 +163,7 @@ final class UniformRapidSuspensionCommand extends MutatingEppToolCommand {
domain.getDomainName(),
"expirationDate",
domain
.getRegistrationExpirationTime()
.getRegistrationExpirationDateTime()
.toString(DateTimeFormat.forPattern("YYYY-MM-dd")),
// period is the number of years to renew the registration for
"period",
@@ -99,8 +99,9 @@ class UnrenewDomainCommand extends ConfirmingCommand {
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 @@ class UnrenewDomainCommand extends ConfirmingCommand {
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 @@ class UnrenewDomainCommand extends ConfirmingCommand {
"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)
@@ -16,7 +16,9 @@ package google.registry.tools;
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.domain.DomainHistory;
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 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand {
private ImmutableMap<Domain, BillingRecurrence> loadDomainsAndRecurrences() {
ImmutableMap.Builder<Domain, BillingRecurrence> 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 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand {
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 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand {
domainAutorenewEndTime.ifPresent(
endTime ->
checkArgument(
endTime.isAfter(now),
endTime.isAfter(toDateTime(now)),
"Domain %s autorenew ended prior to now at %s",
domainName,
endTime));
@@ -24,6 +24,7 @@ import static google.registry.testing.DatabaseHelper.loadByEntity;
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 @@ class DeleteExpiredDomainsActionTest {
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
@@ -26,7 +26,7 @@ import static google.registry.testing.DatabaseHelper.persistActiveHost;
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;
@@ -47,6 +47,7 @@ import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationT
import google.registry.testing.DatabaseHelper;
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;
@@ -201,7 +202,7 @@ class DeleteProberDataActionTest {
.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 +218,7 @@ class DeleteProberDataActionTest {
.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 +238,7 @@ class DeleteProberDataActionTest {
Optional<Domain> 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 +251,7 @@ class DeleteProberDataActionTest {
.build());
action.isDryRun = true;
action.run();
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(END_OF_TIME);
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(END_INSTANT);
}
@Test
@@ -25,6 +25,8 @@ import static google.registry.testing.DatabaseHelper.persistActiveHost;
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 @@ public class ResaveAllEppResourcesPipelineTest {
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
@@ -488,7 +488,7 @@ class EppLifecycleDomainTest extends EppTestCase {
// 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
@@ -182,7 +182,7 @@ public abstract class FlowTestCase<F extends Flow> {
GracePeriod.create(
entry.getKey().getType(),
entry.getKey().getDomainRepoId(),
entry.getKey().getExpirationTime(),
entry.getKey().getExpirationDateTime(),
entry.getKey().getRegistrarId(),
null,
1L),
@@ -361,7 +361,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.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 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
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 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, 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 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
new PollMessage.Autorenew.Builder()
.setTargetId(domain.getDomainName())
.setRegistrarId("TheRegistrar")
.setEventTime(domain.getRegistrationExpirationTime())
.setEventTime(domain.getRegistrationExpirationDateTime())
.setMsg("Domain was auto-renewed.")
.setHistoryEntry(historyEntry)
.build(),
@@ -376,7 +376,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
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 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
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 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
// 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 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
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 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.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");
@@ -247,7 +247,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
@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 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
.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 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
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 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
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)
@@ -201,7 +201,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
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 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
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)
@@ -148,7 +148,8 @@ class DomainTransferApproveFlowTest
.copyConstantFieldsToBuilder()
.setTransferStatus(TransferStatus.CLIENT_APPROVED)
.setPendingTransferExpirationTime(clock.nowUtc())
.setTransferredRegistrationExpirationTime(domain.getRegistrationExpirationTime())
.setTransferredRegistrationExpirationTime(
domain.getRegistrationExpirationDateTime())
.build());
}
@@ -216,7 +217,7 @@ class DomainTransferApproveFlowTest
// 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 @@ class DomainTransferApproveFlowTest
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 @@ class DomainTransferApproveFlowTest
.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 @@ class DomainTransferApproveFlowTest
.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 @@ class DomainTransferApproveFlowTest
.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 @@ class DomainTransferApproveFlowTest
tld,
commandFilename,
expectedXmlFilename,
domain.getRegistrationExpirationTime().plusYears(1),
domain.getRegistrationExpirationDateTime().plusYears(1),
1);
}
@@ -821,7 +822,7 @@ class DomainTransferApproveFlowTest
"tld",
"domain_transfer_approve.xml",
"domain_transfer_approve_response_zero_period.xml",
domain.getRegistrationExpirationTime());
domain.getRegistrationExpirationDateTime());
assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods();
}
@@ -854,7 +855,7 @@ class DomainTransferApproveFlowTest
"tld",
"domain_transfer_approve.xml",
"domain_transfer_approve_response_zero_period_autorenew_grace.xml",
domain.getRegistrationExpirationTime());
domain.getRegistrationExpirationDateTime());
assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods();
}
@@ -114,7 +114,7 @@ class DomainTransferCancelFlowTest
// Setup done; run the test.
assertMutatingFlow(true);
DateTime originalExpirationTime = domain.getRegistrationExpirationTime();
DateTime originalExpirationTime = domain.getRegistrationExpirationDateTime();
ImmutableSet<GracePeriod> originalGracePeriods = domain.getGracePeriods();
DomainTransferData originalTransferData = domain.getTransferData();
runFlowAssertResponse(loadFile("domain_transfer_cancel_response.xml"));
@@ -143,7 +143,8 @@ class DomainTransferQueryFlowTest
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 @@ class DomainTransferQueryFlowTest
// 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);
@@ -88,7 +88,7 @@ class DomainTransferRejectFlowTest
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<GracePeriod> originalGracePeriods = domain.getGracePeriods();
DomainTransferData originalTransferData = domain.getTransferData();
runFlowAssertResponse(loadFile(expectedXmlFilename));
@@ -244,7 +244,8 @@ class DomainTransferRequestFlowTest
.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 @@ class DomainTransferRequestFlowTest
doSuccessfulTest(
commandFilename,
expectedXmlFilename,
domain.getRegistrationExpirationTime().plusYears(1),
domain.getRegistrationExpirationDateTime().plusYears(1),
substitutions,
Optional.empty());
}
@@ -551,7 +552,9 @@ class DomainTransferRequestFlowTest
throws Exception {
clock.advanceOneMilli();
doSuccessfulTest(
commandFilename, expectedXmlFilename, domain.getRegistrationExpirationTime().plusYears(1));
commandFilename,
expectedXmlFilename,
domain.getRegistrationExpirationDateTime().plusYears(1));
}
private void doSuccessfulSuperuserExtensionTest(
@@ -812,7 +815,7 @@ class DomainTransferRequestFlowTest
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 @@ class DomainTransferRequestFlowTest
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 @@ class DomainTransferRequestFlowTest
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 @@ class DomainTransferRequestFlowTest
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 @@ class DomainTransferRequestFlowTest
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 @@ class DomainTransferRequestFlowTest
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 @@ class DomainTransferRequestFlowTest
doSuccessfulTest(
"domain_transfer_request_separate_fees.xml",
"domain_transfer_request_response_fees.xml",
domain.getRegistrationExpirationTime().plusYears(1),
domain.getRegistrationExpirationDateTime().plusYears(1),
new ImmutableMap.Builder<String, String>()
.put("DOMAIN", "expensive-domain.foo")
.put("YEARS", "1")
@@ -1409,7 +1412,7 @@ class DomainTransferRequestFlowTest
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 @@ class DomainTransferRequestFlowTest
doSuccessfulTest(
"domain_transfer_request_separate_fees.xml",
"domain_transfer_request_response_fees.xml",
domain.getRegistrationExpirationTime().plusYears(1),
domain.getRegistrationExpirationDateTime().plusYears(1),
new ImmutableMap.Builder<String, String>()
.put("DOMAIN", "expensive-domain.foo")
.put("YEARS", "1")
@@ -256,7 +256,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
.and()
.hasPersistedCurrentSponsorRegistrarId("NewRegistrar")
.and()
.hasLastTransferTime(domain.getTransferData().getPendingTransferExpirationTime())
.hasLastTransferTime(domain.getTransferData().getPendingTransferExpirationDateTime())
.and()
.hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_UPDATE);
@@ -31,6 +31,10 @@ import static google.registry.testing.DomainSubject.assertAboutDomains;
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;
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 @@ public class DomainTest {
.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 @@ public class DomainTest {
}
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 @@ public class DomainTest {
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 @@ public class DomainTest {
@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 @@ public class DomainTest {
.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 @@ public class DomainTest {
.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 @@ public class DomainTest {
.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 @@ public class DomainTest {
.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 @@ public class DomainTest {
.setTransferData(transferData)
.build());
assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime())
assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime())
.isEqualTo(newExpiration);
}
@@ -801,7 +810,7 @@ public class DomainTest {
.setTransferData(transferData)
.build());
assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime())
assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime())
.isEqualTo(newExpiration);
}
@@ -843,7 +852,7 @@ public class DomainTest {
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 @@ public class DomainTest {
.setTransferData(transferData)
.build());
assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime())
assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime())
.isEqualTo(previousExpiration);
}
@@ -906,7 +915,7 @@ public class DomainTest {
.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 @@ public class DomainTest {
.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);
@@ -68,7 +68,7 @@ public class GracePeriodTest {
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 @@ public class GracePeriodTest {
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 @@ public class GracePeriodTest {
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();
}
@@ -148,15 +148,15 @@ abstract class AbstractEppResourceSubject<
}
public And<S> hasDeletionTime(DateTime deletionTime) {
return hasValue(deletionTime, actual.getDeletionTime(), "getDeletionTime()");
return hasValue(deletionTime, actual.getDeletionDateTime(), "getDeletionTime()");
}
public And<S> hasLastEppUpdateTime(DateTime lastUpdateTime) {
return hasValue(lastUpdateTime, actual.getLastEppUpdateTime(), "has lastEppUpdateTime");
return hasValue(lastUpdateTime, actual.getLastEppUpdateDateTime(), "has lastEppUpdateTime");
}
public And<S> hasLastEppUpdateTimeAtLeast(DateTime before) {
DateTime lastEppUpdateTime = actual.getLastEppUpdateTime();
DateTime lastEppUpdateTime = actual.getLastEppUpdateDateTime();
check("getLastEppUpdateTime()").that(lastEppUpdateTime).isAtLeast(before);
return andChainer();
}
@@ -78,7 +78,7 @@ public final class DomainSubject extends AbstractEppResourceSubject<Domain, Doma
public And<DomainSubject> hasRegistrationExpirationTime(DateTime expiration) {
return hasValue(
expiration, actual.getRegistrationExpirationTime(), "getRegistrationExpirationTime()");
expiration, actual.getRegistrationExpirationDateTime(), "getRegistrationExpirationTime()");
}
public And<DomainSubject> hasLastTransferTime(DateTime lastTransferTime) {
@@ -78,12 +78,12 @@ public class UnrenewDomainCommandTest extends CommandTestCase<UnrenewDomainComma
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 @@ public class UnrenewDomainCommandTest extends CommandTestCase<UnrenewDomainComma
.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");
}
@@ -19,6 +19,7 @@ import static google.registry.testing.DatabaseHelper.loadByEntity;
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 @@ public class ConsoleBulkDomainActionTest extends ConsoleActionBaseTestCase {
{"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 @@ public class ConsoleBulkDomainActionTest extends ConsoleActionBaseTestCase {
"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");
@@ -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.isBeforeOrAt;
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 @@ class DateTimeUtilsTest {
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 @@ class DateTimeUtilsTest {
.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 @@ class DateTimeUtilsTest {
@Test
void testFailure_latestOfEmpty() {
assertThrows(IllegalArgumentException.class, () -> earliestOf(ImmutableList.of()));
assertThrows(IllegalArgumentException.class, () -> latestOf(ImmutableList.of()));
}
@Test
@@ -107,4 +125,32 @@ class DateTimeUtilsTest {
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"));
}
}