Add SQL schema for GracePeriod (#709)

* Add SQL schema for GracePeriod

* Remove the join table

* Add a domainRepoId in GracePeriod

* Move the clone logic to GracePeriod

* Rebase on HEAD
This commit is contained in:
Shicong Huang 2020-08-06 10:26:19 -04:00 committed by GitHub
parent b89af91bda
commit c5fa6343d5
30 changed files with 518 additions and 135 deletions

View file

@ -360,7 +360,8 @@ public class DomainCreateFlow implements TransactionalFlow {
command.getNameservers().stream().collect(toImmutableSet())) command.getNameservers().stream().collect(toImmutableSet()))
.setStatusValues(statuses.build()) .setStatusValues(statuses.build())
.setContacts(command.getContacts()) .setContacts(command.getContacts())
.addGracePeriod(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, createBillingEvent)) .addGracePeriod(
GracePeriod.forBillingEvent(GracePeriodStatus.ADD, repoId, createBillingEvent))
.build(); .build();
entitiesToSave.add( entitiesToSave.add(
newDomain, newDomain,

View file

@ -186,14 +186,18 @@ public final class DomainDeleteFlow implements TransactionalFlow {
DateTime redemptionTime = now.plus(redemptionGracePeriodLength); DateTime redemptionTime = now.plus(redemptionGracePeriodLength);
asyncTaskEnqueuer.enqueueAsyncResave( asyncTaskEnqueuer.enqueueAsyncResave(
existingDomain, now, ImmutableSortedSet.of(redemptionTime, deletionTime)); existingDomain, now, ImmutableSortedSet.of(redemptionTime, deletionTime));
builder.setDeletionTime(deletionTime) builder
.setDeletionTime(deletionTime)
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
// Clear out all old grace periods and add REDEMPTION, which does not include a key to a // Clear out all old grace periods and add REDEMPTION, which does not include a key to a
// billing event because there isn't one for a domain delete. // billing event because there isn't one for a domain delete.
.setGracePeriods(ImmutableSet.of(GracePeriod.createWithoutBillingEvent( .setGracePeriods(
GracePeriodStatus.REDEMPTION, ImmutableSet.of(
redemptionTime, GracePeriod.createWithoutBillingEvent(
clientId))); GracePeriodStatus.REDEMPTION,
existingDomain.getRepoId(),
redemptionTime,
clientId)));
// Note: The expiration time is unchanged, so if it's before the new deletion time, there will // Note: The expiration time is unchanged, so if it's before the new deletion time, there will
// be a "phantom autorenew" where the expiration time advances. No poll message will be // be a "phantom autorenew" where the expiration time advances. No poll message will be
// produced (since we are ending the autorenew recurrences at "now" below) and the billing // produced (since we are ending the autorenew recurrences at "now" below) and the billing

View file

@ -183,7 +183,8 @@ public final class DomainRenewFlow implements TransactionalFlow {
.setAutorenewBillingEvent(newAutorenewEvent.createVKey()) .setAutorenewBillingEvent(newAutorenewEvent.createVKey())
.setAutorenewPollMessage(newAutorenewPollMessage.createVKey()) .setAutorenewPollMessage(newAutorenewPollMessage.createVKey())
.addGracePeriod( .addGracePeriod(
GracePeriod.forBillingEvent(GracePeriodStatus.RENEW, explicitRenewEvent)) GracePeriod.forBillingEvent(
GracePeriodStatus.RENEW, existingDomain.getRepoId(), explicitRenewEvent))
.build(); .build();
EntityChanges entityChanges = EntityChanges entityChanges =
flowCustomLogic.beforeSave( flowCustomLogic.beforeSave(

View file

@ -192,7 +192,10 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
.setGracePeriods( .setGracePeriods(
billingEvent.isPresent() billingEvent.isPresent()
? ImmutableSet.of( ? ImmutableSet.of(
GracePeriod.forBillingEvent(GracePeriodStatus.TRANSFER, billingEvent.get())) GracePeriod.forBillingEvent(
GracePeriodStatus.TRANSFER,
existingDomain.getRepoId(),
billingEvent.get()))
: ImmutableSet.of()) : ImmutableSet.of())
.setLastEppUpdateTime(now) .setLastEppUpdateTime(now)
.setLastEppUpdateClientId(clientId) .setLastEppUpdateClientId(clientId)

View file

@ -14,6 +14,7 @@
package google.registry.model.domain; package google.registry.model.domain;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Entity;
import google.registry.model.EppResource; import google.registry.model.EppResource;
@ -27,9 +28,13 @@ import google.registry.schema.replay.DatastoreAndSqlEntity;
import java.util.Set; import java.util.Set;
import javax.persistence.Access; import javax.persistence.Access;
import javax.persistence.AccessType; import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/** /**
@ -74,6 +79,17 @@ public class DomainBase extends DomainContent
return super.nsHosts; return super.nsHosts;
} }
@Access(AccessType.PROPERTY)
@OneToMany(
cascade = {CascadeType.ALL},
fetch = FetchType.EAGER,
orphanRemoval = true)
@JoinColumn(name = "domainRepoId", referencedColumnName = "repoId")
@SuppressWarnings("UnusedMethod")
private Set<GracePeriod> getInternalGracePeriods() {
return gracePeriods;
}
@Override @Override
public VKey<DomainBase> createVKey() { public VKey<DomainBase> createVKey() {
return VKey.create(DomainBase.class, getRepoId(), Key.create(this)); return VKey.create(DomainBase.class, getRepoId(), Key.create(this));

View file

@ -73,7 +73,6 @@ import javax.persistence.AccessType;
import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides; import javax.persistence.AttributeOverrides;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
@ -234,7 +233,7 @@ public class DomainContent extends EppResource
VKey<PollMessage.Autorenew> autorenewPollMessage; VKey<PollMessage.Autorenew> autorenewPollMessage;
/** The unexpired grace periods for this domain (some of which may not be active yet). */ /** The unexpired grace periods for this domain (some of which may not be active yet). */
@Transient @ElementCollection Set<GracePeriod> gracePeriods; @Transient Set<GracePeriod> gracePeriods;
/** /**
* The id of the signed mark that was used to create this domain in sunrise. * The id of the signed mark that was used to create this domain in sunrise.
@ -260,6 +259,18 @@ public class DomainContent extends EppResource
allContacts = allContacts =
allContacts.stream().map(contact -> contact.reconstitute()).collect(toImmutableSet()); allContacts.stream().map(contact -> contact.reconstitute()).collect(toImmutableSet());
setContactFields(allContacts, true); setContactFields(allContacts, true);
// We have to return the cloned object here because the original object's
// hashcode is not correct due to the change to its domainRepoId. The cloned
// object will have a null hashcode so that it can get a recalculated hashcode
// when its hashCode() is invoked.
// TODO(b/162739503): Remove this after fully migrating to Cloud SQL.
if (gracePeriods != null) {
gracePeriods =
gracePeriods.stream()
.map(gracePeriod -> gracePeriod.cloneWithDomainRepoId(getRepoId()))
.collect(toImmutableSet());
}
} }
@PostLoad @PostLoad
@ -354,6 +365,12 @@ public class DomainContent extends EppResource
this.nsHosts = nsHosts; this.nsHosts = nsHosts;
} }
// Hibernate needs this in order to populate gracePeriods but no one else should ever use it
@SuppressWarnings("UnusedMethod")
private void setInternalGracePeriods(Set<GracePeriod> gracePeriods) {
this.gracePeriods = gracePeriods;
}
public final String getCurrentSponsorClientId() { public final String getCurrentSponsorClientId() {
return getPersistedCurrentSponsorClientId(); return getPersistedCurrentSponsorClientId();
} }
@ -448,6 +465,7 @@ public class DomainContent extends EppResource
ImmutableSet.of( ImmutableSet.of(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.TRANSFER, GracePeriodStatus.TRANSFER,
domain.getRepoId(),
transferExpirationTime.plus( transferExpirationTime.plus(
Registry.get(domain.getTld()).getTransferGracePeriodLength()), Registry.get(domain.getTld()).getTransferGracePeriodLength()),
transferData.getGainingClientId(), transferData.getGainingClientId(),
@ -483,6 +501,7 @@ public class DomainContent extends EppResource
.addGracePeriod( .addGracePeriod(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
lastAutorenewTime.plus( lastAutorenewTime.plus(
Registry.get(domain.getTld()).getAutoRenewGracePeriodLength()), Registry.get(domain.getTld()).getAutoRenewGracePeriodLength()),
domain.getCurrentSponsorClientId(), domain.getCurrentSponsorClientId(),

View file

@ -18,16 +18,14 @@ import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.googlecode.objectify.annotation.Embed; import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Ignore;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Recurring; import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.persistence.VKey; import google.registry.persistence.VKey;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.persistence.Column; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.Index;
import javax.persistence.GenerationType; import javax.persistence.Table;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/** /**
@ -37,75 +35,13 @@ import org.joda.time.DateTime;
* the resource is loaded from Datastore. * the resource is loaded from Datastore.
*/ */
@Embed @Embed
@javax.persistence.Entity @Entity
public class GracePeriod extends ImmutableObject { @Table(indexes = @Index(columnList = "domainRepoId"))
public class GracePeriod extends GracePeriodBase {
@javax.persistence.Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Ignore
/** Unique id required for hibernate representation. */
long id;
/** The type of grace period. */
GracePeriodStatus type;
/** When the grace period ends. */
DateTime expirationTime;
/** The registrar to bill. */
@Column(name = "registrarId")
String clientId;
/**
* The one-time billing event corresponding to the action that triggered this grace period, or
* null if not applicable. Not set for autorenew grace periods (which instead use the field {@code
* billingEventRecurring}) or for redemption grace periods (since deletes have no cost).
*/
// NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
VKey<BillingEvent.OneTime> billingEventOneTime = null;
/**
* The recurring billing event corresponding to the action that triggered this grace period, if
* applicable - i.e. if the action was an autorenew - or null in all other cases.
*/
// NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
VKey<BillingEvent.Recurring> billingEventRecurring = null;
public GracePeriodStatus getType() {
return type;
}
public DateTime getExpirationTime() {
return expirationTime;
}
public String getClientId() {
return clientId;
}
/** Returns true if this GracePeriod has an associated BillingEvent; i.e. if it's refundable. */
public boolean hasBillingEvent() {
return billingEventOneTime != null || billingEventRecurring != null;
}
/**
* Returns the one time billing event. The value will only be non-null if the type of this grace
* period is not AUTO_RENEW.
*/
public VKey<BillingEvent.OneTime> getOneTimeBillingEvent() {
return billingEventOneTime;
}
/**
* Returns the recurring billing event. The value will only be non-null if the type of this grace
* period is AUTO_RENEW.
*/
public VKey<BillingEvent.Recurring> getRecurringBillingEvent() {
return billingEventRecurring;
}
private static GracePeriod createInternal( private static GracePeriod createInternal(
GracePeriodStatus type, GracePeriodStatus type,
String domainRepoId,
DateTime expirationTime, DateTime expirationTime,
String clientId, String clientId,
@Nullable VKey<BillingEvent.OneTime> billingEventOneTime, @Nullable VKey<BillingEvent.OneTime> billingEventOneTime,
@ -117,6 +53,7 @@ public class GracePeriod extends ImmutableObject {
"Recurring billing events must be present on (and only on) autorenew grace periods"); "Recurring billing events must be present on (and only on) autorenew grace periods");
GracePeriod instance = new GracePeriod(); GracePeriod instance = new GracePeriod();
instance.type = checkArgumentNotNull(type); instance.type = checkArgumentNotNull(type);
instance.domainRepoId = checkArgumentNotNull(domainRepoId);
instance.expirationTime = checkArgumentNotNull(expirationTime); instance.expirationTime = checkArgumentNotNull(expirationTime);
instance.clientId = checkArgumentNotNull(clientId); instance.clientId = checkArgumentNotNull(clientId);
instance.billingEventOneTime = billingEventOneTime; instance.billingEventOneTime = billingEventOneTime;
@ -133,32 +70,51 @@ public class GracePeriod extends ImmutableObject {
*/ */
public static GracePeriod create( public static GracePeriod create(
GracePeriodStatus type, GracePeriodStatus type,
String domainRepoId,
DateTime expirationTime, DateTime expirationTime,
String clientId, String clientId,
@Nullable VKey<BillingEvent.OneTime> billingEventOneTime) { @Nullable VKey<BillingEvent.OneTime> billingEventOneTime) {
return createInternal(type, expirationTime, clientId, billingEventOneTime, null); return createInternal(type, domainRepoId, expirationTime, clientId, billingEventOneTime, null);
} }
/** Creates a GracePeriod for a Recurring billing event. */ /** Creates a GracePeriod for a Recurring billing event. */
public static GracePeriod createForRecurring( public static GracePeriod createForRecurring(
GracePeriodStatus type, GracePeriodStatus type,
String domainRepoId,
DateTime expirationTime, DateTime expirationTime,
String clientId, String clientId,
VKey<Recurring> billingEventRecurring) { VKey<Recurring> billingEventRecurring) {
checkArgumentNotNull(billingEventRecurring, "billingEventRecurring cannot be null"); checkArgumentNotNull(billingEventRecurring, "billingEventRecurring cannot be null");
return createInternal(type, expirationTime, clientId, null, billingEventRecurring); return createInternal(
type, domainRepoId, expirationTime, clientId, null, billingEventRecurring);
} }
/** Creates a GracePeriod with no billing event. */ /** Creates a GracePeriod with no billing event. */
public static GracePeriod createWithoutBillingEvent( public static GracePeriod createWithoutBillingEvent(
GracePeriodStatus type, DateTime expirationTime, String clientId) { GracePeriodStatus type, String domainRepoId, DateTime expirationTime, String clientId) {
return createInternal(type, expirationTime, clientId, null, null); return createInternal(type, domainRepoId, expirationTime, clientId, null, null);
} }
/** Constructs a GracePeriod of the given type from the provided one-time BillingEvent. */ /** Constructs a GracePeriod of the given type from the provided one-time BillingEvent. */
public static GracePeriod forBillingEvent( public static GracePeriod forBillingEvent(
GracePeriodStatus type, BillingEvent.OneTime billingEvent) { GracePeriodStatus type, String domainRepoId, BillingEvent.OneTime billingEvent) {
return create( return create(
type, billingEvent.getBillingTime(), billingEvent.getClientId(), billingEvent.createVKey()); type,
domainRepoId,
billingEvent.getBillingTime(),
billingEvent.getClientId(),
billingEvent.createVKey());
} }
/**
* Returns a clone of this {@link GracePeriod} with {@link #domainRepoId} set to the given value.
*
* <p>TODO(b/162739503): Remove this function after fully migrating to Cloud SQL.
*/
public GracePeriod cloneWithDomainRepoId(String domainRepoId) {
GracePeriod clone = clone(this);
clone.domainRepoId = checkArgumentNotNull(domainRepoId);
return clone;
}
} }

View file

@ -0,0 +1,114 @@
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.model.domain;
import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Ignore;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.persistence.VKey;
import javax.persistence.Column;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.MappedSuperclass;
import org.joda.time.DateTime;
/** Base class containing common fields and methods for {@link GracePeriod}. */
@Embed
@MappedSuperclass
public class GracePeriodBase extends ImmutableObject {
/** Unique id required for hibernate representation. */
@javax.persistence.Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Ignore
Long id;
/** Repository id for the domain which this grace period belongs to. */
@Ignore
@Column(nullable = false)
String domainRepoId;
/** The type of grace period. */
@Column(nullable = false)
@Enumerated(EnumType.STRING)
GracePeriodStatus type;
/** When the grace period ends. */
@Column(nullable = false)
DateTime expirationTime;
/** The registrar to bill. */
@Column(name = "registrarId", nullable = false)
String clientId;
/**
* The one-time billing event corresponding to the action that triggered this grace period, or
* null if not applicable. Not set for autorenew grace periods (which instead use the field {@code
* billingEventRecurring}) or for redemption grace periods (since deletes have no cost).
*/
// NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
@Column(name = "billing_event_id")
VKey<OneTime> billingEventOneTime = null;
/**
* The recurring billing event corresponding to the action that triggered this grace period, if
* applicable - i.e. if the action was an autorenew - or null in all other cases.
*/
// NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
@Column(name = "billing_recurrence_id")
VKey<BillingEvent.Recurring> billingEventRecurring = null;
public GracePeriodStatus getType() {
return type;
}
public String getDomainRepoId() {
return domainRepoId;
}
public DateTime getExpirationTime() {
return expirationTime;
}
public String getClientId() {
return clientId;
}
/** Returns true if this GracePeriod has an associated BillingEvent; i.e. if it's refundable. */
public boolean hasBillingEvent() {
return billingEventOneTime != null || billingEventRecurring != null;
}
/**
* Returns the one time billing event. The value will only be non-null if the type of this grace
* period is not AUTO_RENEW.
*/
public VKey<BillingEvent.OneTime> getOneTimeBillingEvent() {
return billingEventOneTime;
}
/**
* Returns the recurring billing event. The value will only be non-null if the type of this grace
* period is AUTO_RENEW.
*/
public VKey<BillingEvent.Recurring> getRecurringBillingEvent() {
return billingEventRecurring;
}
}

View file

@ -117,9 +117,10 @@ public class ResaveEntityActionTest {
@Test @Test
void test_domainPendingDeletion_isResavedAndReenqueued() { void test_domainPendingDeletion_isResavedAndReenqueued() {
DomainBase newDomain = newDomainBase("domain.tld");
DomainBase domain = DomainBase domain =
persistResource( persistResource(
newDomainBase("domain.tld") newDomain
.asBuilder() .asBuilder()
.setDeletionTime(clock.nowUtc().plusDays(35)) .setDeletionTime(clock.nowUtc().plusDays(35))
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
@ -127,6 +128,7 @@ public class ResaveEntityActionTest {
ImmutableSet.of( ImmutableSet.of(
GracePeriod.createWithoutBillingEvent( GracePeriod.createWithoutBillingEvent(
GracePeriodStatus.REDEMPTION, GracePeriodStatus.REDEMPTION,
newDomain.getRepoId(),
clock.nowUtc().plusDays(30), clock.nowUtc().plusDays(30),
"TheRegistrar"))) "TheRegistrar")))
.build()); .build());

View file

@ -161,6 +161,7 @@ public class DomainBaseUtilTest {
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.ADD, GracePeriodStatus.ADD,
"4-COM",
fakeClock.nowUtc().plusDays(1), fakeClock.nowUtc().plusDays(1),
"registrar", "registrar",
null)) null))

View file

@ -214,7 +214,11 @@ class InitSqlPipelineTest {
.setSmdId("smdid") .setSmdId("smdid")
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.ADD, fakeClock.nowUtc().plusDays(1), "registrar", null)) GracePeriodStatus.ADD,
"4-COM",
fakeClock.nowUtc().plusDays(1),
"registrar",
null))
.build()); .build());
exportDir = store.export(exportRootDir.getAbsolutePath(), ALL_KINDS, ImmutableSet.of()); exportDir = store.export(exportRootDir.getAbsolutePath(), ALL_KINDS, ImmutableSet.of());
commitLogDir = Files.createDirectory(tmpDir.resolve("commits")).toFile(); commitLogDir = Files.createDirectory(tmpDir.resolve("commits")).toFile();

View file

@ -185,6 +185,7 @@ public abstract class FlowTestCase<F extends Flow> {
builder.put( builder.put(
GracePeriod.create( GracePeriod.create(
entry.getKey().getType(), entry.getKey().getType(),
entry.getKey().getDomainRepoId(),
entry.getKey().getExpirationTime(), entry.getKey().getExpirationTime(),
entry.getKey().getClientId(), entry.getKey().getClientId(),
null), null),

View file

@ -325,7 +325,8 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertGracePeriods( assertGracePeriods(
domain.getGracePeriods(), domain.getGracePeriods(),
ImmutableMap.of( ImmutableMap.of(
GracePeriod.create(GracePeriodStatus.ADD, billingTime, "TheRegistrar", null), GracePeriod.create(
GracePeriodStatus.ADD, domain.getRepoId(), billingTime, "TheRegistrar", null),
createBillingEvent)); createBillingEvent));
assertDnsTasksEnqueued(getUniqueIdFromCommand()); assertDnsTasksEnqueued(getUniqueIdFromCommand());
assertEppResourceIndexEntityFor(domain); assertEppResourceIndexEntityFor(domain);

View file

@ -195,6 +195,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
ImmutableSet.of( ImmutableSet.of(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
A_MONTH_AGO.plusDays(45), A_MONTH_AGO.plusDays(45),
"TheRegistrar", "TheRegistrar",
autorenewBillingEvent.createVKey()))) autorenewBillingEvent.createVKey())))
@ -290,7 +291,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
void testDryRun() throws Exception { void testDryRun() throws Exception {
setUpSuccessfulTest(); setUpSuccessfulTest();
setUpGracePeriods( setUpGracePeriods(
GracePeriod.create(GracePeriodStatus.ADD, TIME_BEFORE_FLOW.plusDays(1), "foo", null)); GracePeriod.create(
GracePeriodStatus.ADD, domain.getRepoId(), TIME_BEFORE_FLOW.plusDays(1), "foo", null));
dryRunFlowAssertResponse(loadFile("generic_success_response.xml")); dryRunFlowAssertResponse(loadFile("generic_success_response.xml"));
} }
@ -314,7 +316,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
setUpSuccessfulTest(); setUpSuccessfulTest();
BillingEvent.OneTime graceBillingEvent = BillingEvent.OneTime graceBillingEvent =
persistResource(createBillingEvent(Reason.CREATE, Money.of(USD, 123))); persistResource(createBillingEvent(Reason.CREATE, Money.of(USD, 123)));
setUpGracePeriods(GracePeriod.forBillingEvent(gracePeriodStatus, graceBillingEvent)); setUpGracePeriods(
GracePeriod.forBillingEvent(gracePeriodStatus, domain.getRepoId(), graceBillingEvent));
// We should see exactly one poll message, which is for the autorenew 1 month in the future. // We should see exactly one poll message, which is for the autorenew 1 month in the future.
assertPollMessages(createAutorenewPollMessage("TheRegistrar").build()); assertPollMessages(createAutorenewPollMessage("TheRegistrar").build());
clock.advanceOneMilli(); clock.advanceOneMilli();
@ -388,9 +391,14 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
BillingEvent.OneTime renewBillingEvent = BillingEvent.OneTime renewBillingEvent =
persistResource(createBillingEvent(Reason.RENEW, Money.of(USD, 456))); persistResource(createBillingEvent(Reason.RENEW, Money.of(USD, 456)));
setUpGracePeriods( setUpGracePeriods(
GracePeriod.forBillingEvent(GracePeriodStatus.RENEW, renewBillingEvent), GracePeriod.forBillingEvent(GracePeriodStatus.RENEW, domain.getRepoId(), renewBillingEvent),
// This grace period has no associated billing event, so it won't cause a cancellation. // This grace period has no associated billing event, so it won't cause a cancellation.
GracePeriod.create(GracePeriodStatus.TRANSFER, TIME_BEFORE_FLOW.plusDays(1), "foo", null)); GracePeriod.create(
GracePeriodStatus.TRANSFER,
domain.getRepoId(),
TIME_BEFORE_FLOW.plusDays(1),
"foo",
null));
// We should see exactly one poll message, which is for the autorenew 1 month in the future. // We should see exactly one poll message, which is for the autorenew 1 month in the future.
assertPollMessages(createAutorenewPollMessage("TheRegistrar").build()); assertPollMessages(createAutorenewPollMessage("TheRegistrar").build());
DateTime expectedExpirationTime = domain.getRegistrationExpirationTime().minusYears(2); DateTime expectedExpirationTime = domain.getRegistrationExpirationTime().minusYears(2);
@ -424,6 +432,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.containsExactly( .containsExactly(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.REDEMPTION, GracePeriodStatus.REDEMPTION,
domain.getRepoId(),
clock.nowUtc().plus(Registry.get("tld").getRedemptionGracePeriodLength()), clock.nowUtc().plus(Registry.get("tld").getRedemptionGracePeriodLength()),
"TheRegistrar", "TheRegistrar",
null)); null));
@ -624,6 +633,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.containsExactly( .containsExactly(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.REDEMPTION, GracePeriodStatus.REDEMPTION,
domain.getRepoId(),
clock.nowUtc().plus(Registry.get("tld").getRedemptionGracePeriodLength()), clock.nowUtc().plus(Registry.get("tld").getRedemptionGracePeriodLength()),
"TheRegistrar", "TheRegistrar",
null)); null));
@ -696,7 +706,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
BillingEvent.OneTime graceBillingEvent = BillingEvent.OneTime graceBillingEvent =
persistResource(createBillingEvent(Reason.CREATE, Money.of(USD, 123))); persistResource(createBillingEvent(Reason.CREATE, Money.of(USD, 123)));
// Use a grace period so that the delete is immediate, simplifying the assertions below. // Use a grace period so that the delete is immediate, simplifying the assertions below.
setUpGracePeriods(GracePeriod.forBillingEvent(GracePeriodStatus.ADD, graceBillingEvent)); setUpGracePeriods(
GracePeriod.forBillingEvent(GracePeriodStatus.ADD, domain.getRepoId(), graceBillingEvent));
// Add a nameserver. // Add a nameserver.
HostResource host = persistResource(newHostResource("ns1.example.tld")); HostResource host = persistResource(newHostResource("ns1.example.tld"));
persistResource( persistResource(
@ -1004,7 +1015,11 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
setUpSuccessfulTest(); setUpSuccessfulTest();
setUpGracePeriods( setUpGracePeriods(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.ADD, TIME_BEFORE_FLOW.plusDays(1), "TheRegistrar", null)); GracePeriodStatus.ADD,
domain.getRepoId(),
TIME_BEFORE_FLOW.plusDays(1),
"TheRegistrar",
null));
setUpGracePeriodDurations(); setUpGracePeriodDurations();
clock.advanceOneMilli(); clock.advanceOneMilli();
earlierHistoryEntry = earlierHistoryEntry =
@ -1027,7 +1042,11 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
setUpSuccessfulTest(); setUpSuccessfulTest();
setUpGracePeriods( setUpGracePeriods(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.ADD, TIME_BEFORE_FLOW.plusDays(1), "TheRegistrar", null)); GracePeriodStatus.ADD,
domain.getRepoId(),
TIME_BEFORE_FLOW.plusDays(1),
"TheRegistrar",
null));
setUpGracePeriodDurations(); setUpGracePeriodDurations();
clock.advanceOneMilli(); clock.advanceOneMilli();
earlierHistoryEntry = earlierHistoryEntry =
@ -1081,6 +1100,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.containsExactly( .containsExactly(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.REDEMPTION, GracePeriodStatus.REDEMPTION,
domain.getRepoId(),
clock.nowUtc().plus(standardDays(15)), clock.nowUtc().plus(standardDays(15)),
"TheRegistrar", "TheRegistrar",
null)); null));
@ -1127,6 +1147,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
.containsExactly( .containsExactly(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.REDEMPTION, GracePeriodStatus.REDEMPTION,
domain.getRepoId(),
clock.nowUtc().plus(standardDays(15)), clock.nowUtc().plus(standardDays(15)),
"TheRegistrar", "TheRegistrar",
null)); null));

View file

@ -308,7 +308,8 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
domain domain
.asBuilder() .asBuilder()
.addGracePeriod( .addGracePeriod(
GracePeriod.create(gracePeriodStatus, clock.nowUtc().plusDays(1), "foo", null)) GracePeriod.create(
gracePeriodStatus, domain.getRepoId(), clock.nowUtc().plusDays(1), "foo", null))
.setCreationClientId("NewRegistrar") .setCreationClientId("NewRegistrar")
.setCreationTimeForTest(DateTime.parse("2003-11-26T22:00:00.0Z")) .setCreationTimeForTest(DateTime.parse("2003-11-26T22:00:00.0Z"))
.setRegistrationExpirationTime(DateTime.parse("2005-11-26T22:00:00.0Z")) .setRegistrationExpirationTime(DateTime.parse("2005-11-26T22:00:00.0Z"))
@ -337,7 +338,11 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
.asBuilder() .asBuilder()
.addGracePeriod( .addGracePeriod(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, clock.nowUtc().plusDays(1), "foo", recurringVKey)) GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"foo",
recurringVKey))
.build()); .build());
doSuccessfulTest("domain_info_response_autorenewperiod.xml", false); doSuccessfulTest("domain_info_response_autorenewperiod.xml", false);
} }
@ -352,7 +357,11 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
.asBuilder() .asBuilder()
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.REDEMPTION, clock.nowUtc().plusDays(1), "foo", null)) GracePeriodStatus.REDEMPTION,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"foo",
null))
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
.build()); .build());
doSuccessfulTest("domain_info_response_redemptionperiod.xml", false); doSuccessfulTest("domain_info_response_redemptionperiod.xml", false);
@ -367,7 +376,11 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
.asBuilder() .asBuilder()
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.RENEW, clock.nowUtc().plusDays(1), "foo", null)) GracePeriodStatus.RENEW,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"foo",
null))
.build()); .build());
doSuccessfulTest("domain_info_response_renewperiod.xml", false); doSuccessfulTest("domain_info_response_renewperiod.xml", false);
} }
@ -381,10 +394,18 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
.asBuilder() .asBuilder()
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.RENEW, clock.nowUtc().plusDays(1), "foo", null)) GracePeriodStatus.RENEW,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"foo",
null))
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.RENEW, clock.nowUtc().plusDays(2), "foo", null)) GracePeriodStatus.RENEW,
domain.getRepoId(),
clock.nowUtc().plusDays(2),
"foo",
null))
.build()); .build());
doSuccessfulTest("domain_info_response_renewperiod.xml", false); doSuccessfulTest("domain_info_response_renewperiod.xml", false);
} }
@ -398,7 +419,11 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
.asBuilder() .asBuilder()
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.TRANSFER, clock.nowUtc().plusDays(1), "foo", null)) GracePeriodStatus.TRANSFER,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"foo",
null))
.build()); .build());
doSuccessfulTest("domain_info_response_transferperiod.xml", false); doSuccessfulTest("domain_info_response_transferperiod.xml", false);
} }
@ -421,10 +446,19 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
domain domain
.asBuilder() .asBuilder()
.addGracePeriod( .addGracePeriod(
GracePeriod.create(GracePeriodStatus.ADD, clock.nowUtc().plusDays(1), "foo", null)) GracePeriod.create(
GracePeriodStatus.ADD,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"foo",
null))
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.RENEW, clock.nowUtc().plusDays(2), "foo", null)) GracePeriodStatus.RENEW,
domain.getRepoId(),
clock.nowUtc().plusDays(2),
"foo",
null))
.build()); .build());
doSuccessfulTest("domain_info_response_stackedaddrenewperiod.xml", false); doSuccessfulTest("domain_info_response_stackedaddrenewperiod.xml", false);
} }
@ -437,7 +471,12 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
domain domain
.asBuilder() .asBuilder()
.addGracePeriod( .addGracePeriod(
GracePeriod.create(GracePeriodStatus.ADD, clock.nowUtc().plusDays(1), "foo", null)) GracePeriod.create(
GracePeriodStatus.ADD,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"foo",
null))
.setDsData( .setDsData(
ImmutableSet.of( ImmutableSet.of(
DelegationSignerData.create( DelegationSignerData.create(

View file

@ -236,6 +236,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
ImmutableMap.of( ImmutableMap.of(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.RENEW, GracePeriodStatus.RENEW,
domain.getRepoId(),
clock.nowUtc().plus(Registry.get("tld").getRenewGracePeriodLength()), clock.nowUtc().plus(Registry.get("tld").getRenewGracePeriodLength()),
renewalClientId, renewalClientId,
null), null),

View file

@ -112,7 +112,11 @@ class DomainRestoreRequestFlowTest
.setDeletionTime(clock.nowUtc().plusDays(35)) .setDeletionTime(clock.nowUtc().plusDays(35))
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.REDEMPTION, clock.nowUtc().plusDays(1), "foo", null)) GracePeriodStatus.REDEMPTION,
domain.getRepoId(),
clock.nowUtc().plusDays(1),
"foo",
null))
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
.setDeletePollMessage( .setDeletePollMessage(
persistResource( persistResource(

View file

@ -288,6 +288,7 @@ class DomainTransferApproveFlowTest
ImmutableMap.of( ImmutableMap.of(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.TRANSFER, GracePeriodStatus.TRANSFER,
domain.getRepoId(),
clock.nowUtc().plus(registry.getTransferGracePeriodLength()), clock.nowUtc().plus(registry.getTransferGracePeriodLength()),
"NewRegistrar", "NewRegistrar",
null), null),
@ -649,6 +650,7 @@ class DomainTransferApproveFlowTest
.addGracePeriod( .addGracePeriod(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()), autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()),
"TheRegistrar", "TheRegistrar",
existingAutorenewEvent)) existingAutorenewEvent))

View file

@ -332,6 +332,7 @@ class DomainTransferRequestFlowTest
ImmutableMap.of( ImmutableMap.of(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.TRANSFER, GracePeriodStatus.TRANSFER,
domain.getRepoId(),
implicitTransferTime.plus(registry.getTransferGracePeriodLength()), implicitTransferTime.plus(registry.getTransferGracePeriodLength()),
"NewRegistrar", "NewRegistrar",
null), null),
@ -962,6 +963,7 @@ class DomainTransferRequestFlowTest
.addGracePeriod( .addGracePeriod(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()), autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()),
"TheRegistrar", "TheRegistrar",
existingAutorenewEvent)) existingAutorenewEvent))
@ -1088,6 +1090,7 @@ class DomainTransferRequestFlowTest
.addGracePeriod( .addGracePeriod(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()), autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()),
"TheRegistrar", "TheRegistrar",
domain.getAutorenewBillingEvent())) domain.getAutorenewBillingEvent()))
@ -1117,6 +1120,7 @@ class DomainTransferRequestFlowTest
.addGracePeriod( .addGracePeriod(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()), autorenewTime.plus(Registry.get("tld").getAutoRenewGracePeriodLength()),
"TheRegistrar", "TheRegistrar",
existingAutorenewEvent)) existingAutorenewEvent))

View file

@ -385,10 +385,11 @@ public class BillingEventTest extends EntityTestCase {
@Test @Test
void testSuccess_cancellation_forGracePeriod_withOneTime() { void testSuccess_cancellation_forGracePeriod_withOneTime() {
BillingEvent.Cancellation newCancellation = BillingEvent.Cancellation.forGracePeriod( BillingEvent.Cancellation newCancellation =
GracePeriod.forBillingEvent(GracePeriodStatus.ADD, oneTime), BillingEvent.Cancellation.forGracePeriod(
historyEntry2, GracePeriod.forBillingEvent(GracePeriodStatus.ADD, domain.getRepoId(), oneTime),
"foo.tld"); historyEntry2,
"foo.tld");
// Set ID to be the same to ignore for the purposes of comparison. // Set ID to be the same to ignore for the purposes of comparison.
newCancellation = newCancellation.asBuilder().setId(cancellationOneTime.getId()).build(); newCancellation = newCancellation.asBuilder().setId(cancellationOneTime.getId()).build();
assertThat(newCancellation).isEqualTo(cancellationOneTime); assertThat(newCancellation).isEqualTo(cancellationOneTime);
@ -400,6 +401,7 @@ public class BillingEventTest extends EntityTestCase {
BillingEvent.Cancellation.forGracePeriod( BillingEvent.Cancellation.forGracePeriod(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
now.plusYears(1).plusDays(45), now.plusYears(1).plusDays(45),
"a registrar", "a registrar",
recurring.createVKey()), recurring.createVKey()),
@ -418,7 +420,10 @@ public class BillingEventTest extends EntityTestCase {
() -> () ->
BillingEvent.Cancellation.forGracePeriod( BillingEvent.Cancellation.forGracePeriod(
GracePeriod.createWithoutBillingEvent( GracePeriod.createWithoutBillingEvent(
GracePeriodStatus.REDEMPTION, now.plusDays(1), "a registrar"), GracePeriodStatus.REDEMPTION,
domain.getRepoId(),
now.plusDays(1),
"a registrar"),
historyEntry, historyEntry,
"foo.tld")); "foo.tld"));
assertThat(thrown).hasMessageThat().contains("grace period without billing event"); assertThat(thrown).hasMessageThat().contains("grace period without billing event");

View file

@ -18,6 +18,7 @@ import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableO
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm; import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.testing.SqlHelper.assertThrowForeignKeyViolation; import static google.registry.testing.SqlHelper.assertThrowForeignKeyViolation;
import static google.registry.testing.SqlHelper.saveRegistrar; 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.START_OF_TIME;
import static org.joda.time.DateTimeZone.UTC; import static org.joda.time.DateTimeZone.UTC;
@ -25,6 +26,7 @@ import com.google.common.collect.ImmutableSet;
import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact.Type; import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.launch.LaunchNotice; import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DelegationSignerData; import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.AuthInfo.PasswordAuth; import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
@ -100,6 +102,8 @@ public class DomainBaseSqlTest {
.setLaunchNotice( .setLaunchNotice(
LaunchNotice.create("tcnid", "validatorId", START_OF_TIME, START_OF_TIME)) LaunchNotice.create("tcnid", "validatorId", START_OF_TIME, START_OF_TIME))
.setSmdId("smdid") .setSmdId("smdid")
.addGracePeriod(
GracePeriod.create(GracePeriodStatus.ADD, "4-COM", END_OF_TIME, "registrar1", null))
.build(); .build();
host = host =

View file

@ -154,6 +154,7 @@ public class DomainBaseTest extends EntityTestCase {
.addGracePeriod( .addGracePeriod(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.ADD, GracePeriodStatus.ADD,
"4-COM",
fakeClock.nowUtc().plusDays(1), fakeClock.nowUtc().plusDays(1),
"registrar", "registrar",
null)) null))
@ -371,7 +372,11 @@ public class DomainBaseTest extends EntityTestCase {
// Okay for billing event to be null since the point of this grace period is just // Okay for billing event to be null since the point of this grace period is just
// to check that the transfer will clear all existing grace periods. // to check that the transfer will clear all existing grace periods.
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.ADD, fakeClock.nowUtc().plusDays(100), "foo", null)) GracePeriodStatus.ADD,
domain.getRepoId(),
fakeClock.nowUtc().plusDays(100),
"foo",
null))
.build(); .build();
DomainBase afterTransfer = domain.cloneProjectedAtTime(fakeClock.nowUtc().plusDays(1)); DomainBase afterTransfer = domain.cloneProjectedAtTime(fakeClock.nowUtc().plusDays(1));
DateTime newExpirationTime = oldExpirationTime.plusYears(1); DateTime newExpirationTime = oldExpirationTime.plusYears(1);
@ -382,6 +387,7 @@ public class DomainBaseTest extends EntityTestCase {
.containsExactly( .containsExactly(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.TRANSFER, GracePeriodStatus.TRANSFER,
domain.getRepoId(),
fakeClock fakeClock
.nowUtc() .nowUtc()
.plusDays(1) .plusDays(1)
@ -499,9 +505,24 @@ public class DomainBaseTest extends EntityTestCase {
void testStackedGracePeriods() { void testStackedGracePeriods() {
ImmutableList<GracePeriod> gracePeriods = ImmutableList<GracePeriod> gracePeriods =
ImmutableList.of( ImmutableList.of(
GracePeriod.create(GracePeriodStatus.ADD, fakeClock.nowUtc().plusDays(3), "foo", null), GracePeriod.create(
GracePeriod.create(GracePeriodStatus.ADD, fakeClock.nowUtc().plusDays(2), "bar", null), GracePeriodStatus.ADD,
GracePeriod.create(GracePeriodStatus.ADD, fakeClock.nowUtc().plusDays(1), "baz", null)); domain.getRepoId(),
fakeClock.nowUtc().plusDays(3),
"foo",
null),
GracePeriod.create(
GracePeriodStatus.ADD,
domain.getRepoId(),
fakeClock.nowUtc().plusDays(2),
"bar",
null),
GracePeriod.create(
GracePeriodStatus.ADD,
domain.getRepoId(),
fakeClock.nowUtc().plusDays(1),
"baz",
null));
domain = domain.asBuilder().setGracePeriods(ImmutableSet.copyOf(gracePeriods)).build(); domain = domain.asBuilder().setGracePeriods(ImmutableSet.copyOf(gracePeriods)).build();
for (int i = 1; i < 3; ++i) { for (int i = 1; i < 3; ++i) {
assertThat(domain.cloneProjectedAtTime(fakeClock.nowUtc().plusDays(i)).getGracePeriods()) assertThat(domain.cloneProjectedAtTime(fakeClock.nowUtc().plusDays(i)).getGracePeriods())
@ -513,14 +534,32 @@ public class DomainBaseTest extends EntityTestCase {
void testGracePeriodsByType() { void testGracePeriodsByType() {
ImmutableSet<GracePeriod> addGracePeriods = ImmutableSet<GracePeriod> addGracePeriods =
ImmutableSet.of( ImmutableSet.of(
GracePeriod.create(GracePeriodStatus.ADD, fakeClock.nowUtc().plusDays(3), "foo", null), GracePeriod.create(
GracePeriod.create(GracePeriodStatus.ADD, fakeClock.nowUtc().plusDays(1), "baz", null)); GracePeriodStatus.ADD,
domain.getRepoId(),
fakeClock.nowUtc().plusDays(3),
"foo",
null),
GracePeriod.create(
GracePeriodStatus.ADD,
domain.getRepoId(),
fakeClock.nowUtc().plusDays(1),
"baz",
null));
ImmutableSet<GracePeriod> renewGracePeriods = ImmutableSet<GracePeriod> renewGracePeriods =
ImmutableSet.of( ImmutableSet.of(
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.RENEW, fakeClock.nowUtc().plusDays(3), "foo", null), GracePeriodStatus.RENEW,
domain.getRepoId(),
fakeClock.nowUtc().plusDays(3),
"foo",
null),
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.RENEW, fakeClock.nowUtc().plusDays(1), "baz", null)); GracePeriodStatus.RENEW,
domain.getRepoId(),
fakeClock.nowUtc().plusDays(1),
"baz",
null));
domain = domain =
domain domain
.asBuilder() .asBuilder()
@ -589,6 +628,7 @@ public class DomainBaseTest extends EntityTestCase {
.containsExactly( .containsExactly(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
oldExpirationTime oldExpirationTime
.plusYears(2) .plusYears(2)
.plus(Registry.get("com").getAutoRenewGracePeriodLength()), .plus(Registry.get("com").getAutoRenewGracePeriodLength()),
@ -757,6 +797,7 @@ public class DomainBaseTest extends EntityTestCase {
ImmutableSet.of( ImmutableSet.of(
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW, GracePeriodStatus.AUTO_RENEW,
domain.getRepoId(),
now.plusDays(1), now.plusDays(1),
"NewRegistrar", "NewRegistrar",
recurringBillKey))) recurringBillKey)))

View file

@ -63,8 +63,9 @@ public class GracePeriodTest {
@Test @Test
void testSuccess_forBillingEvent() { void testSuccess_forBillingEvent() {
GracePeriod gracePeriod = GracePeriod.forBillingEvent(GracePeriodStatus.ADD, onetime); GracePeriod gracePeriod = GracePeriod.forBillingEvent(GracePeriodStatus.ADD, "1-TEST", onetime);
assertThat(gracePeriod.getType()).isEqualTo(GracePeriodStatus.ADD); assertThat(gracePeriod.getType()).isEqualTo(GracePeriodStatus.ADD);
assertThat(gracePeriod.getDomainRepoId()).isEqualTo("1-TEST");
assertThat(gracePeriod.getOneTimeBillingEvent()).isEqualTo(onetime.createVKey()); assertThat(gracePeriod.getOneTimeBillingEvent()).isEqualTo(onetime.createVKey());
assertThat(gracePeriod.getRecurringBillingEvent()).isNull(); assertThat(gracePeriod.getRecurringBillingEvent()).isNull();
assertThat(gracePeriod.getClientId()).isEqualTo("TheRegistrar"); assertThat(gracePeriod.getClientId()).isEqualTo("TheRegistrar");
@ -74,9 +75,11 @@ public class GracePeriodTest {
@Test @Test
void testSuccess_createWithoutBillingEvent() { void testSuccess_createWithoutBillingEvent() {
GracePeriod gracePeriod = GracePeriod.createWithoutBillingEvent( GracePeriod gracePeriod =
GracePeriodStatus.REDEMPTION, now, "TheRegistrar"); GracePeriod.createWithoutBillingEvent(
GracePeriodStatus.REDEMPTION, "1-TEST", now, "TheRegistrar");
assertThat(gracePeriod.getType()).isEqualTo(GracePeriodStatus.REDEMPTION); assertThat(gracePeriod.getType()).isEqualTo(GracePeriodStatus.REDEMPTION);
assertThat(gracePeriod.getDomainRepoId()).isEqualTo("1-TEST");
assertThat(gracePeriod.getOneTimeBillingEvent()).isNull(); assertThat(gracePeriod.getOneTimeBillingEvent()).isNull();
assertThat(gracePeriod.getRecurringBillingEvent()).isNull(); assertThat(gracePeriod.getRecurringBillingEvent()).isNull();
assertThat(gracePeriod.getClientId()).isEqualTo("TheRegistrar"); assertThat(gracePeriod.getClientId()).isEqualTo("TheRegistrar");
@ -89,7 +92,7 @@ public class GracePeriodTest {
IllegalArgumentException thrown = IllegalArgumentException thrown =
assertThrows( assertThrows(
IllegalArgumentException.class, IllegalArgumentException.class,
() -> GracePeriod.forBillingEvent(GracePeriodStatus.AUTO_RENEW, onetime)); () -> GracePeriod.forBillingEvent(GracePeriodStatus.AUTO_RENEW, "1-TEST", onetime));
assertThat(thrown).hasMessageThat().contains("autorenew"); assertThat(thrown).hasMessageThat().contains("autorenew");
} }
@ -101,6 +104,7 @@ public class GracePeriodTest {
() -> () ->
GracePeriod.createForRecurring( GracePeriod.createForRecurring(
GracePeriodStatus.RENEW, GracePeriodStatus.RENEW,
"1-TEST",
now.plusDays(1), now.plusDays(1),
"TheRegistrar", "TheRegistrar",
VKey.create(Recurring.class, 12345))); VKey.create(Recurring.class, 12345)));

View file

@ -278,6 +278,7 @@ public class DomainBaseToXjcConverterTest {
ImmutableSet.of( ImmutableSet.of(
GracePeriod.forBillingEvent( GracePeriod.forBillingEvent(
GracePeriodStatus.RENEW, GracePeriodStatus.RENEW,
domain.getRepoId(),
persistResource( persistResource(
new BillingEvent.OneTime.Builder() new BillingEvent.OneTime.Builder()
.setReason(Reason.RENEW) .setReason(Reason.RENEW)
@ -291,6 +292,7 @@ public class DomainBaseToXjcConverterTest {
.build())), .build())),
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.TRANSFER, GracePeriodStatus.TRANSFER,
domain.getRepoId(),
DateTime.parse("1920-01-01T00:00:00Z"), DateTime.parse("1920-01-01T00:00:00Z"),
"foo", "foo",
null))) null)))

View file

@ -122,6 +122,7 @@ final class RdeFixtures {
ImmutableSet.of( ImmutableSet.of(
GracePeriod.forBillingEvent( GracePeriod.forBillingEvent(
GracePeriodStatus.RENEW, GracePeriodStatus.RENEW,
domain.getRepoId(),
persistResource( persistResource(
new BillingEvent.OneTime.Builder() new BillingEvent.OneTime.Builder()
.setReason(Reason.RENEW) .setReason(Reason.RENEW)
@ -135,6 +136,7 @@ final class RdeFixtures {
.build())), .build())),
GracePeriod.create( GracePeriod.create(
GracePeriodStatus.TRANSFER, GracePeriodStatus.TRANSFER,
domain.getRepoId(),
DateTime.parse("1992-01-01T00:00:00Z"), DateTime.parse("1992-01-01T00:00:00Z"),
"foo", "foo",
null))) null)))

View file

@ -504,9 +504,10 @@ public class DatastoreHelper {
DateTime creationTime, DateTime creationTime,
DateTime expirationTime) { DateTime expirationTime) {
String domainName = String.format("%s.%s", label, tld); String domainName = String.format("%s.%s", label, tld);
String repoId = generateNewDomainRoid(tld);
DomainBase domain = DomainBase domain =
new DomainBase.Builder() new DomainBase.Builder()
.setRepoId(generateNewDomainRoid(tld)) .setRepoId(repoId)
.setDomainName(domainName) .setDomainName(domainName)
.setPersistedCurrentSponsorClientId("TheRegistrar") .setPersistedCurrentSponsorClientId("TheRegistrar")
.setCreationClientId("TheRegistrar") .setCreationClientId("TheRegistrar")
@ -519,7 +520,7 @@ public class DatastoreHelper {
DesignatedContact.create(Type.TECH, contact.createVKey()))) DesignatedContact.create(Type.TECH, contact.createVKey())))
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("fooBAR"))) .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("fooBAR")))
.addGracePeriod( .addGracePeriod(
GracePeriod.create(GracePeriodStatus.ADD, now.plusDays(10), "foo", null)) GracePeriod.create(GracePeriodStatus.ADD, repoId, now.plusDays(10), "foo", null))
.build(); .build();
HistoryEntry historyEntryDomainCreate = HistoryEntry historyEntryDomainCreate =
persistResource( persistResource(

View file

@ -228,11 +228,12 @@ class DomainWhoisResponseTest {
VKey<ContactResource> adminResourceKey = adminContact.createVKey(); VKey<ContactResource> adminResourceKey = adminContact.createVKey();
VKey<ContactResource> techResourceKey = techContact.createVKey(); VKey<ContactResource> techResourceKey = techContact.createVKey();
String repoId = "3-TLD";
domainBase = domainBase =
persistResource( persistResource(
new DomainBase.Builder() new DomainBase.Builder()
.setDomainName("example.tld") .setDomainName("example.tld")
.setRepoId("3-TLD") .setRepoId(repoId)
.setLastEppUpdateTime(DateTime.parse("2009-05-29T20:13:00Z")) .setLastEppUpdateTime(DateTime.parse("2009-05-29T20:13:00Z"))
.setCreationTimeForTest(DateTime.parse("2000-10-08T00:45:00Z")) .setCreationTimeForTest(DateTime.parse("2000-10-08T00:45:00Z"))
.setRegistrationExpirationTime(DateTime.parse("2010-10-08T00:44:59Z")) .setRegistrationExpirationTime(DateTime.parse("2010-10-08T00:44:59Z"))
@ -252,8 +253,9 @@ class DomainWhoisResponseTest {
.setDsData(ImmutableSet.of(DelegationSignerData.create(1, 2, 3, "deadface"))) .setDsData(ImmutableSet.of(DelegationSignerData.create(1, 2, 3, "deadface")))
.setGracePeriods( .setGracePeriods(
ImmutableSet.of( ImmutableSet.of(
GracePeriod.create(GracePeriodStatus.ADD, END_OF_TIME, "", null), GracePeriod.create(GracePeriodStatus.ADD, repoId, END_OF_TIME, "", null),
GracePeriod.create(GracePeriodStatus.TRANSFER, END_OF_TIME, "", null))) GracePeriod.create(
GracePeriodStatus.TRANSFER, repoId, END_OF_TIME, "", null)))
.build()); .build());
} }

View file

@ -0,0 +1,41 @@
-- Copyright 2020 The Nomulus Authors. All Rights Reserved.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
create table "GracePeriod" (
id bigserial not null,
billing_event_id int8,
billing_recurrence_id int8,
registrar_id text not null,
domain_repo_id text not null,
expiration_time timestamptz not null,
type text not null,
primary key (id)
);
alter table if exists "GracePeriod"
add constraint FK2mys4hojm6ev2g9tmy5aq6m7g
foreign key (domain_repo_id)
references "Domain";
alter table if exists "GracePeriod"
add constraint fk_grace_period_billing_event_id
foreign key (billing_event_id)
references "BillingEvent";
alter table if exists "GracePeriod"
add constraint fk_grace_period_billing_recurrence_id
foreign key (billing_recurrence_id)
references "BillingRecurrence";
create index IDXj1mtx98ndgbtb1bkekahms18w on "GracePeriod" (domain_repo_id);

View file

@ -339,11 +339,12 @@ create sequence history_id_sequence start 1 increment 1;
create table "GracePeriod" ( create table "GracePeriod" (
id bigserial not null, id bigserial not null,
billing_event_one_time int8, billing_event_id int8,
billing_event_recurring int8, billing_recurrence_id int8,
registrar_id text, registrar_id text not null,
expiration_time timestamptz, domain_repo_id text not null,
type int4, expiration_time timestamptz not null,
type text not null,
primary key (id) primary key (id)
); );
@ -596,6 +597,7 @@ create index IDXrh4xmrot9bd63o382ow9ltfig on "DomainHistory" (creation_time);
create index IDXaro1omfuaxjwmotk3vo00trwm on "DomainHistory" (history_registrar_id); create index IDXaro1omfuaxjwmotk3vo00trwm on "DomainHistory" (history_registrar_id);
create index IDXsu1nam10cjes9keobapn5jvxj on "DomainHistory" (history_type); create index IDXsu1nam10cjes9keobapn5jvxj on "DomainHistory" (history_type);
create index IDX6w3qbtgce93cal2orjg1tw7b7 on "DomainHistory" (history_modification_time); create index IDX6w3qbtgce93cal2orjg1tw7b7 on "DomainHistory" (history_modification_time);
create index IDXj1mtx98ndgbtb1bkekahms18w on "GracePeriod" (domain_repo_id);
create index IDXfg2nnjlujxo6cb9fha971bq2n on "HostHistory" (creation_time); create index IDXfg2nnjlujxo6cb9fha971bq2n on "HostHistory" (creation_time);
create index IDX1iy7njgb7wjmj9piml4l2g0qi on "HostHistory" (history_registrar_id); create index IDX1iy7njgb7wjmj9piml4l2g0qi on "HostHistory" (history_registrar_id);
create index IDXkkwbwcwvrdkkqothkiye4jiff on "HostHistory" (host_name); create index IDXkkwbwcwvrdkkqothkiye4jiff on "HostHistory" (host_name);
@ -632,6 +634,11 @@ create index spec11threatmatch_check_date_idx on "Spec11ThreatMatch" (check_date
foreign key (domain_repo_id) foreign key (domain_repo_id)
references "Domain"; references "Domain";
alter table if exists "GracePeriod"
add constraint FK2mys4hojm6ev2g9tmy5aq6m7g
foreign key (domain_repo_id)
references "Domain";
alter table if exists "PremiumEntry" alter table if exists "PremiumEntry"
add constraint FKo0gw90lpo1tuee56l0nb6y6g5 add constraint FKo0gw90lpo1tuee56l0nb6y6g5
foreign key (revision_id) foreign key (revision_id)

View file

@ -488,6 +488,40 @@ CREATE TABLE public."DomainHost" (
); );
--
-- Name: GracePeriod; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."GracePeriod" (
id bigint NOT NULL,
billing_event_id bigint,
billing_recurrence_id bigint,
registrar_id text NOT NULL,
domain_repo_id text NOT NULL,
expiration_time timestamp with time zone NOT NULL,
type text NOT NULL
);
--
-- Name: GracePeriod_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public."GracePeriod_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: GracePeriod_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public."GracePeriod_id_seq" OWNED BY public."GracePeriod".id;
-- --
-- Name: HostHistory; Type: TABLE; Schema: public; Owner: - -- Name: HostHistory; Type: TABLE; Schema: public; Owner: -
-- --
@ -900,6 +934,13 @@ ALTER TABLE ONLY public."BillingRecurrence" ALTER COLUMN billing_recurrence_id S
ALTER TABLE ONLY public."ClaimsList" ALTER COLUMN revision_id SET DEFAULT nextval('public."ClaimsList_revision_id_seq"'::regclass); ALTER TABLE ONLY public."ClaimsList" ALTER COLUMN revision_id SET DEFAULT nextval('public."ClaimsList_revision_id_seq"'::regclass);
--
-- Name: GracePeriod id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."GracePeriod" ALTER COLUMN id SET DEFAULT nextval('public."GracePeriod_id_seq"'::regclass);
-- --
-- Name: PollMessage poll_message_id; Type: DEFAULT; Schema: public; Owner: - -- Name: PollMessage poll_message_id; Type: DEFAULT; Schema: public; Owner: -
-- --
@ -1022,6 +1063,14 @@ ALTER TABLE ONLY public."Domain"
ADD CONSTRAINT "Domain_pkey" PRIMARY KEY (repo_id); ADD CONSTRAINT "Domain_pkey" PRIMARY KEY (repo_id);
--
-- Name: GracePeriod GracePeriod_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."GracePeriod"
ADD CONSTRAINT "GracePeriod_pkey" PRIMARY KEY (id);
-- --
-- Name: HostHistory HostHistory_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- Name: HostHistory HostHistory_pkey; Type: CONSTRAINT; Schema: public; Owner: -
-- --
@ -1310,6 +1359,13 @@ CREATE INDEX idxhmv411mdqo5ibn4vy7ykxpmlv ON public."BillingEvent" USING btree (
CREATE INDEX idxhp33wybmb6tbpr1bq7ttwk8je ON public."ContactHistory" USING btree (history_registrar_id); CREATE INDEX idxhp33wybmb6tbpr1bq7ttwk8je ON public."ContactHistory" USING btree (history_registrar_id);
--
-- Name: idxj1mtx98ndgbtb1bkekahms18w; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxj1mtx98ndgbtb1bkekahms18w ON public."GracePeriod" USING btree (domain_repo_id);
-- --
-- Name: idxj77pfwhui9f0i7wjq6lmibovj; Type: INDEX; Schema: public; Owner: - -- Name: idxj77pfwhui9f0i7wjq6lmibovj; Type: INDEX; Schema: public; Owner: -
-- --
@ -1488,6 +1544,14 @@ ALTER TABLE ONLY public."RegistryLock"
ADD CONSTRAINT fk2lhcwpxlnqijr96irylrh1707 FOREIGN KEY (relock_revision_id) REFERENCES public."RegistryLock"(revision_id); ADD CONSTRAINT fk2lhcwpxlnqijr96irylrh1707 FOREIGN KEY (relock_revision_id) REFERENCES public."RegistryLock"(revision_id);
--
-- Name: GracePeriod fk2mys4hojm6ev2g9tmy5aq6m7g; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."GracePeriod"
ADD CONSTRAINT fk2mys4hojm6ev2g9tmy5aq6m7g FOREIGN KEY (domain_repo_id) REFERENCES public."Domain"(repo_id);
-- --
-- Name: Domain fk2u3srsfbei272093m3b3xwj23; Type: FK CONSTRAINT; Schema: public; Owner: - -- Name: Domain fk2u3srsfbei272093m3b3xwj23; Type: FK CONSTRAINT; Schema: public; Owner: -
-- --
@ -1728,6 +1792,22 @@ ALTER TABLE ONLY public."DomainHost"
ADD CONSTRAINT fk_domainhost_host_valid FOREIGN KEY (host_repo_id) REFERENCES public."HostResource"(repo_id); ADD CONSTRAINT fk_domainhost_host_valid FOREIGN KEY (host_repo_id) REFERENCES public."HostResource"(repo_id);
--
-- Name: GracePeriod fk_grace_period_billing_event_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."GracePeriod"
ADD CONSTRAINT fk_grace_period_billing_event_id FOREIGN KEY (billing_event_id) REFERENCES public."BillingEvent"(billing_event_id);
--
-- Name: GracePeriod fk_grace_period_billing_recurrence_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."GracePeriod"
ADD CONSTRAINT fk_grace_period_billing_recurrence_id FOREIGN KEY (billing_recurrence_id) REFERENCES public."BillingRecurrence"(billing_recurrence_id);
-- --
-- Name: HostResource fk_host_resource_superordinate_domain; Type: FK CONSTRAINT; Schema: public; Owner: - -- Name: HostResource fk_host_resource_superordinate_domain; Type: FK CONSTRAINT; Schema: public; Owner: -
-- --