Add SQL schema for GracePeriodHistory (#746)

* Add schema for GracePeriodHistory

Rebase on HEAD

Rebase on HEAD

Rebase on HEAD and rename column

Use OfyService to generate id

Refactor GracePeriodsSubject

Rebase on HEAD

Remove GracePeriodSubject and GracePeriodsSubject

Rebase on HEAD

Rebase on HEAD

Rebase on HEAD

Add gracePeriodHistoryRevisionId and remove some foreign key

* Rebase on HEAD
This commit is contained in:
Shicong Huang 2020-11-12 10:06:58 -05:00 committed by GitHub
parent 1349fa4cfc
commit 8625e44cfd
23 changed files with 4813 additions and 4091 deletions

View file

@ -24,6 +24,7 @@ import com.googlecode.objectify.annotation.EntitySubclass;
import com.googlecode.objectify.annotation.Ignore;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.domain.GracePeriod.GracePeriodHistory;
import google.registry.model.domain.secdns.DomainDsDataHistory;
import google.registry.model.host.HostResource;
import google.registry.model.reporting.DomainTransactionRecord;
@ -118,6 +119,24 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
})
Set<DomainDsDataHistory> dsDataHistories;
@OneToMany(
cascade = {CascadeType.ALL},
fetch = FetchType.EAGER,
orphanRemoval = true)
@JoinColumns({
@JoinColumn(
name = "domainHistoryRevisionId",
referencedColumnName = "historyRevisionId",
insertable = false,
updatable = false),
@JoinColumn(
name = "domainRepoId",
referencedColumnName = "domainRepoId",
insertable = false,
updatable = false)
})
Set<GracePeriodHistory> gracePeriodHistories;
@Override
@Nullable
@Access(AccessType.PROPERTY)
@ -205,6 +224,10 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
return VKey.create(DomainBase.class, getDomainRepoId());
}
public Set<GracePeriodHistory> getGracePeriodHistories() {
return nullToEmptyImmutableCopy(gracePeriodHistories);
}
/** Creates a {@link VKey} instance for this entity. */
public VKey<DomainHistory> createVKey() {
return VKey.create(
@ -327,6 +350,10 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
nullToEmptyImmutableCopy(instance.domainContent.getDsData()).stream()
.map(dsData -> DomainDsDataHistory.createFrom(instance.id, dsData))
.collect(toImmutableSet());
instance.gracePeriodHistories =
nullToEmptyImmutableCopy(instance.domainContent.getGracePeriods()).stream()
.map(gracePeriod -> GracePeriodHistory.createFrom(instance.id, gracePeriod))
.collect(toImmutableSet());
}
return instance;
}

View file

@ -17,7 +17,9 @@ package google.registry.model.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.annotations.VisibleForTesting;
import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.OnLoad;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.domain.rgp.GracePeriodStatus;
@ -25,7 +27,10 @@ import google.registry.model.ofy.ObjectifyService;
import google.registry.persistence.VKey;
import google.registry.schema.replay.DatastoreAndSqlEntity;
import javax.annotation.Nullable;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
import org.joda.time.DateTime;
@ -41,20 +46,36 @@ import org.joda.time.DateTime;
@Table(indexes = @Index(columnList = "domainRepoId"))
public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntity {
@Id
@Access(AccessType.PROPERTY)
@Override
public long getGracePeriodId() {
return super.getGracePeriodId();
}
// TODO(b/169873747): Remove this method after explicitly re-saving all domain entities.
@OnLoad
void onLoad() {
if (gracePeriodId == null) {
gracePeriodId = ObjectifyService.allocateId();
}
}
private static GracePeriod createInternal(
GracePeriodStatus type,
String domainRepoId,
DateTime expirationTime,
String clientId,
@Nullable VKey<BillingEvent.OneTime> billingEventOneTime,
@Nullable VKey<BillingEvent.Recurring> billingEventRecurring) {
@Nullable VKey<BillingEvent.Recurring> billingEventRecurring,
@Nullable Long gracePeriodId) {
checkArgument((billingEventOneTime == null) || (billingEventRecurring == null),
"A grace period can have at most one billing event");
checkArgument(
(billingEventRecurring != null) == GracePeriodStatus.AUTO_RENEW.equals(type),
"Recurring billing events must be present on (and only on) autorenew grace periods");
GracePeriod instance = new GracePeriod();
instance.id = ObjectifyService.allocateId();
instance.gracePeriodId = gracePeriodId == null ? ObjectifyService.allocateId() : gracePeriodId;
instance.type = checkArgumentNotNull(type);
instance.domainRepoId = checkArgumentNotNull(domainRepoId);
instance.expirationTime = checkArgumentNotNull(expirationTime);
@ -79,7 +100,28 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit
DateTime expirationTime,
String clientId,
@Nullable VKey<BillingEvent.OneTime> billingEventOneTime) {
return createInternal(type, domainRepoId, expirationTime, clientId, billingEventOneTime, null);
return createInternal(
type, domainRepoId, expirationTime, clientId, billingEventOneTime, null, null);
}
/**
* Creates a GracePeriod for an (optional) OneTime billing event and a given {@link
* #gracePeriodId}.
*
* <p>Normal callers should always use {@link #forBillingEvent} instead, assuming they do not need
* to avoid loading the BillingEvent from Datastore. This method should typically be called only
* from test code to explicitly construct GracePeriods.
*/
@VisibleForTesting
public static GracePeriod create(
GracePeriodStatus type,
String domainRepoId,
DateTime expirationTime,
String clientId,
@Nullable VKey<BillingEvent.OneTime> billingEventOneTime,
@Nullable Long gracePeriodId) {
return createInternal(
type, domainRepoId, expirationTime, clientId, billingEventOneTime, null, gracePeriodId);
}
/** Creates a GracePeriod for a Recurring billing event. */
@ -91,13 +133,27 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit
VKey<Recurring> billingEventRecurring) {
checkArgumentNotNull(billingEventRecurring, "billingEventRecurring cannot be null");
return createInternal(
type, domainRepoId, expirationTime, clientId, null, billingEventRecurring);
type, domainRepoId, expirationTime, clientId, null, billingEventRecurring, null);
}
/** Creates a GracePeriod for a Recurring billing event and a given {@link #gracePeriodId}. */
@VisibleForTesting
public static GracePeriod createForRecurring(
GracePeriodStatus type,
String domainRepoId,
DateTime expirationTime,
String clientId,
VKey<Recurring> billingEventRecurring,
@Nullable Long gracePeriodId) {
checkArgumentNotNull(billingEventRecurring, "billingEventRecurring cannot be null");
return createInternal(
type, domainRepoId, expirationTime, clientId, null, billingEventRecurring, gracePeriodId);
}
/** Creates a GracePeriod with no billing event. */
public static GracePeriod createWithoutBillingEvent(
GracePeriodStatus type, String domainRepoId, DateTime expirationTime, String clientId) {
return createInternal(type, domainRepoId, expirationTime, clientId, null, null);
return createInternal(type, domainRepoId, expirationTime, clientId, null, null, null);
}
/** Constructs a GracePeriod of the given type from the provided one-time BillingEvent. */
@ -119,7 +175,6 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit
*/
public GracePeriod cloneAfterOfyLoad(String domainRepoId) {
GracePeriod clone = clone(this);
clone.id = ObjectifyService.allocateId();
clone.domainRepoId = checkArgumentNotNull(domainRepoId);
clone.restoreHistoryIds();
return clone;
@ -136,4 +191,49 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit
clone.billingEventRecurring = recurring;
return clone;
}
/**
* Returns a clone of this {@link GracePeriod} with prepopulated {@link #gracePeriodId} generated
* by {@link ObjectifyService#allocateId()}.
*
* <p>TODO(shicong): Figure out how to generate the id only when the entity is used for Cloud SQL.
*/
@VisibleForTesting
public GracePeriod cloneWithPrepopulatedId() {
GracePeriod clone = clone(this);
clone.gracePeriodId = ObjectifyService.allocateId();
return clone;
}
/** Entity class to represent a historic {@link GracePeriod}. */
@Entity(name = "GracePeriodHistory")
@Table(indexes = @Index(columnList = "domainRepoId"))
static class GracePeriodHistory extends GracePeriodBase {
@Id Long gracePeriodHistoryRevisionId;
/** ID for the associated {@link DomainHistory} entity. */
Long domainHistoryRevisionId;
@Override
@Access(AccessType.PROPERTY)
public long getGracePeriodId() {
return super.getGracePeriodId();
}
static GracePeriodHistory createFrom(long historyRevisionId, GracePeriod gracePeriod) {
GracePeriodHistory instance = new GracePeriodHistory();
instance.gracePeriodHistoryRevisionId = ObjectifyService.allocateId();
instance.domainHistoryRevisionId = historyRevisionId;
instance.gracePeriodId = gracePeriod.gracePeriodId;
instance.type = gracePeriod.type;
instance.domainRepoId = gracePeriod.domainRepoId;
instance.expirationTime = gracePeriod.expirationTime;
instance.clientId = gracePeriod.clientId;
instance.billingEventOneTime = gracePeriod.billingEventOneTime;
instance.billingEventOneTimeHistoryId = gracePeriod.billingEventOneTimeHistoryId;
instance.billingEventRecurring = gracePeriod.billingEventRecurring;
instance.billingEventRecurringHistoryId = gracePeriod.billingEventRecurringHistoryId;
return instance;
}
}
}

View file

@ -26,21 +26,23 @@ import google.registry.persistence.VKey;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.joda.time.DateTime;
/** Base class containing common fields and methods for {@link GracePeriod}. */
@Embed
@MappedSuperclass
@Access(AccessType.FIELD)
public class GracePeriodBase extends ImmutableObject {
/** Unique id required for hibernate representation. */
@javax.persistence.Id
@Ignore
Long id;
@Transient Long gracePeriodId;
/** Repository id for the domain which this grace period belongs to. */
@Ignore
@ -85,8 +87,8 @@ public class GracePeriodBase extends ImmutableObject {
@Column(name = "billing_recurrence_history_id")
Long billingEventRecurringHistoryId;
public long getId() {
return id;
public long getGracePeriodId() {
return gracePeriodId;
}
public GracePeriodStatus getType() {
@ -105,6 +107,12 @@ public class GracePeriodBase extends ImmutableObject {
return clientId;
}
/** This method is private because it is only used by Hibernate. */
@SuppressWarnings("unused")
private void setGracePeriodId(long gracePeriodId) {
this.gracePeriodId = gracePeriodId;
}
/** Returns true if this GracePeriod has an associated BillingEvent; i.e. if it's refundable. */
public boolean hasBillingEvent() {
return billingEventOneTime != null || billingEventRecurring != null;

View file

@ -46,6 +46,7 @@
<class>google.registry.model.domain.DomainBase</class>
<class>google.registry.model.domain.DomainHistory</class>
<class>google.registry.model.domain.GracePeriod</class>
<class>google.registry.model.domain.GracePeriod$GracePeriodHistory</class>
<class>google.registry.model.domain.secdns.DelegationSignerData</class>
<class>google.registry.model.domain.secdns.DomainDsDataHistory</class>
<class>google.registry.model.domain.token.AllocationToken</class>

View file

@ -805,7 +805,7 @@ class EppLifecycleDomainTest extends EppTestCase {
// As the losing registrar, read the request poll message, and then ack it.
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
String messageId = "1-C-EXAMPLE-20-26-2001";
String messageId = "1-C-EXAMPLE-18-24-2001";
assertThatCommand("poll.xml")
.atTime("2001-01-01T00:01:00Z")
.hasResponse("poll_response_domain_transfer_request.xml", ImmutableMap.of("ID", messageId));
@ -814,7 +814,7 @@ class EppLifecycleDomainTest extends EppTestCase {
.hasResponse("poll_ack_response_empty.xml");
// Five days in the future, expect a server approval poll message to the loser, and ack it.
messageId = "1-C-EXAMPLE-20-25-2001";
messageId = "1-C-EXAMPLE-18-23-2001";
assertThatCommand("poll.xml")
.atTime("2001-01-06T00:01:00Z")
.hasResponse(
@ -826,7 +826,7 @@ class EppLifecycleDomainTest extends EppTestCase {
assertThatLogoutSucceeds();
// Also expect a server approval poll message to the winner, with the transfer request trid.
messageId = "1-C-EXAMPLE-20-24-2001";
messageId = "1-C-EXAMPLE-18-22-2001";
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("poll.xml")
.atTime("2001-01-06T00:02:00Z")

View file

@ -183,7 +183,8 @@ public abstract class FlowTestCase<F extends Flow> {
entry.getKey().getDomainRepoId(),
entry.getKey().getExpirationTime(),
entry.getKey().getClientId(),
null),
null,
1L),
stripBillingEventId(entry.getValue()));
}
return builder.build();

View file

@ -436,7 +436,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
domain.getRepoId(),
clock.nowUtc().plus(Registry.get("tld").getRedemptionGracePeriodLength()),
"TheRegistrar",
null));
null,
resource.getGracePeriods().iterator().next().getGracePeriodId()));
assertDeletionPollMessageFor(resource, "Domain deleted.");
}
@ -637,7 +638,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
domain.getRepoId(),
clock.nowUtc().plus(Registry.get("tld").getRedemptionGracePeriodLength()),
"TheRegistrar",
null));
null,
domain.getGracePeriods().iterator().next().getGracePeriodId()));
// The poll message (in the future) to the losing registrar for implicit ack should be gone.
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).isEmpty();
// The poll message in the future to the gaining registrar should be gone too, but there
@ -1104,7 +1106,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
domain.getRepoId(),
clock.nowUtc().plus(standardDays(15)),
"TheRegistrar",
null));
null,
resource.getGracePeriods().iterator().next().getGracePeriodId()));
assertDeletionPollMessageFor(resource, "Deleted by registry administrator.");
}
@ -1151,7 +1154,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
domain.getRepoId(),
clock.nowUtc().plus(standardDays(15)),
"TheRegistrar",
null));
null,
resource.getGracePeriods().iterator().next().getGracePeriodId()));
assertDeletionPollMessageFor(resource, "Deleted by registry administrator.");
}

View file

@ -87,8 +87,7 @@ public final class ImmutableObjectSubject extends Subject {
}
}
private static Map<Field, Object> filterFields(
ImmutableObject original, String... ignoredFields) {
public static Map<Field, Object> filterFields(ImmutableObject original, String... ignoredFields) {
ImmutableSet<String> ignoredFieldSet = ImmutableSet.copyOf(ignoredFields);
Map<Field, Object> originalFields = ModelUtils.getFieldValues(original);
// don't use ImmutableMap or a stream->collect model since we can have nulls

View file

@ -24,7 +24,6 @@ import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.USD;
import static org.joda.time.DateTimeZone.UTC;
import static org.junit.jupiter.api.Assertions.fail;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@ -118,7 +117,8 @@ public class DomainBaseSqlTest {
LaunchNotice.create("tcnid", "validatorId", START_OF_TIME, START_OF_TIME))
.setSmdId("smdid")
.addGracePeriod(
GracePeriod.create(GracePeriodStatus.ADD, "4-COM", END_OF_TIME, "registrar1", null))
GracePeriod.create(
GracePeriodStatus.ADD, "4-COM", END_OF_TIME, "registrar1", null, 100L))
.build();
host =
@ -240,7 +240,12 @@ public class DomainBaseSqlTest {
.asBuilder()
.addGracePeriod(
GracePeriod.create(
GracePeriodStatus.RENEW, "4-COM", END_OF_TIME, "registrar1", null))
GracePeriodStatus.RENEW,
"4-COM",
END_OF_TIME,
"registrar1",
null,
200L))
.build();
jpaTm().put(modified);
});
@ -249,38 +254,12 @@ public class DomainBaseSqlTest {
.transact(
() -> {
DomainBase persisted = jpaTm().load(domain.createVKey());
assertThat(persisted.getGracePeriods().size()).isEqualTo(2);
persisted
.getGracePeriods()
.forEach(
gracePeriod -> {
assertThat(gracePeriod.id).isNotNull();
if (gracePeriod.getType() == GracePeriodStatus.ADD) {
assertAboutImmutableObjects()
.that(gracePeriod)
.isEqualExceptFields(
GracePeriod.create(
GracePeriodStatus.ADD,
"4-COM",
END_OF_TIME,
"registrar1",
null),
"id");
} else if (gracePeriod.getType() == GracePeriodStatus.RENEW) {
assertAboutImmutableObjects()
.that(gracePeriod)
.isEqualExceptFields(
GracePeriod.create(
GracePeriodStatus.RENEW,
"4-COM",
END_OF_TIME,
"registrar1",
null),
"id");
} else {
fail("Unexpected GracePeriod: " + gracePeriod);
}
});
assertThat(persisted.getGracePeriods())
.containsExactly(
GracePeriod.create(
GracePeriodStatus.ADD, "4-COM", END_OF_TIME, "registrar1", null, 100L),
GracePeriod.create(
GracePeriodStatus.RENEW, "4-COM", END_OF_TIME, "registrar1", null, 200L));
assertEqualDomainExcept(persisted, "gracePeriods");
});
@ -327,7 +306,12 @@ public class DomainBaseSqlTest {
.asBuilder()
.addGracePeriod(
GracePeriod.create(
GracePeriodStatus.ADD, "4-COM", END_OF_TIME, "registrar1", null))
GracePeriodStatus.ADD,
"4-COM",
END_OF_TIME,
"registrar1",
null,
100L))
.build();
jpaTm().put(modified);
});
@ -336,13 +320,10 @@ public class DomainBaseSqlTest {
.transact(
() -> {
DomainBase persisted = jpaTm().load(domain.createVKey());
assertThat(persisted.getGracePeriods().size()).isEqualTo(1);
assertAboutImmutableObjects()
.that(persisted.getGracePeriods().iterator().next())
.isEqualExceptFields(
assertThat(persisted.getGracePeriods())
.containsExactly(
GracePeriod.create(
GracePeriodStatus.ADD, "4-COM", END_OF_TIME, "registrar1", null),
"id");
GracePeriodStatus.ADD, "4-COM", END_OF_TIME, "registrar1", null, 100L));
assertEqualDomainExcept(persisted, "gracePeriods");
});
}

View file

@ -413,7 +413,8 @@ public class DomainBaseTest extends EntityTestCase {
.plusDays(1)
.plus(Registry.get("com").getTransferGracePeriodLength()),
"winner",
transferBillingEvent.createVKey()));
transferBillingEvent.createVKey(),
afterTransfer.getGracePeriods().iterator().next().getGracePeriodId()));
// If we project after the grace period expires all should be the same except the grace period.
DomainBase afterGracePeriod =
domain.cloneProjectedAtTime(
@ -653,7 +654,8 @@ public class DomainBaseTest extends EntityTestCase {
.plusYears(2)
.plus(Registry.get("com").getAutoRenewGracePeriodLength()),
renewedThreeTimes.getCurrentSponsorClientId(),
renewedThreeTimes.autorenewBillingEvent));
renewedThreeTimes.autorenewBillingEvent,
renewedThreeTimes.getGracePeriods().iterator().next().getGracePeriodId()));
}
@Test

View file

@ -24,6 +24,7 @@ import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.newContactResourceWithRoid;
import static google.registry.testing.DatastoreHelper.newDomainBase;
import static google.registry.testing.DatastoreHelper.newHostResourceWithRoid;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableSet;
@ -33,7 +34,9 @@ import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainContent;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
import google.registry.model.domain.Period;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostResource;
@ -55,7 +58,7 @@ public class DomainHistoryTest extends EntityTestCase {
@TestSqlOnly
void testPersistence() {
DomainBase domain = createDomainWithContactsAndHosts();
DomainBase domain = addGracePeriodForSql(createDomainWithContactsAndHosts());
DomainHistory domainHistory = createDomainHistory(domain);
jpaTm().transact(() -> jpaTm().insert(domainHistory));
@ -70,7 +73,7 @@ public class DomainHistoryTest extends EntityTestCase {
@TestSqlOnly
void testLegacyPersistence_nullResource() {
DomainBase domain = createDomainWithContactsAndHosts();
DomainBase domain = addGracePeriodForSql(createDomainWithContactsAndHosts());
DomainHistory domainHistory =
createDomainHistory(domain).asBuilder().setDomainContent(null).build();
jpaTm().transact(() -> jpaTm().insert(domainHistory));
@ -146,6 +149,17 @@ public class DomainHistoryTest extends EntityTestCase {
return domain;
}
private static DomainBase addGracePeriodForSql(DomainBase domainBase) {
return domainBase
.asBuilder()
.setGracePeriods(
ImmutableSet.of(
GracePeriod.create(
GracePeriodStatus.ADD, "domainRepoId", END_OF_TIME, "clientId", null)
.cloneWithPrepopulatedId()))
.build();
}
static void assertDomainHistoriesEqual(DomainHistory one, DomainHistory two) {
assertAboutImmutableObjects()
.that(one)

View file

@ -118,7 +118,12 @@ public class LegacyHistoryObjectTest extends EntityTestCase {
assertAboutImmutableObjects()
.that(legacyHistoryEntry)
.isEqualExceptFields(
fromObjectify, "domainContent", "domainRepoId", "nsHosts", "dsDataHistories");
fromObjectify,
"domainContent",
"domainRepoId",
"nsHosts",
"dsDataHistories",
"gracePeriodHistories");
assertThat(fromObjectify instanceof DomainHistory).isTrue();
DomainHistory legacyDomainHistory = (DomainHistory) fromObjectify;
@ -136,7 +141,8 @@ public class LegacyHistoryObjectTest extends EntityTestCase {
"domainTransactionRecords",
"otherClientId",
"nsHosts",
"dsDataHistories");
"dsDataHistories",
"gracePeriodHistories");
assertThat(nullToEmpty(legacyDomainHistory.getNsHosts()))
.isEqualTo(nullToEmpty(legacyHistoryFromSql.getNsHosts()));
}

View file

@ -124,19 +124,19 @@ class DedupeRecurringBillingEventIdsCommandTest
@Test
void testResaveAssociatedDomainAndOneTimeBillingEventCorrectly() throws Exception {
assertThat(recurring1.getId()).isEqualTo(recurring2.getId());
GracePeriod gracePeriod =
GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW,
domain1.getRepoId(),
now.plusDays(45),
"a registrar",
recurring1.createVKey());
domain1 =
persistResource(
domain1
.asBuilder()
.setAutorenewBillingEvent(recurring1.createVKey())
.setGracePeriods(
ImmutableSet.of(
GracePeriod.createForRecurring(
GracePeriodStatus.AUTO_RENEW,
domain1.getRepoId(),
now.plusDays(45),
"a registrar",
recurring1.createVKey())))
.setGracePeriods(ImmutableSet.of(gracePeriod))
.setTransferData(
new DomainTransferData.Builder()
.setServerApproveAutorenewEvent(recurring1.createVKey())
@ -201,7 +201,8 @@ class DedupeRecurringBillingEventIdsCommandTest
domain1.getRepoId(),
now.plusDays(45),
"a registrar",
newRecurring.createVKey()));
newRecurring.createVKey(),
gracePeriod.getGracePeriodId()));
assertThat(persistedDomain.getTransferData().getServerApproveAutorenewEvent())
.isEqualTo(newRecurring.createVKey());
assertThat(persistedDomain.getTransferData().getServerApproveEntities())

View file

@ -108,7 +108,7 @@ class EppLifecycleToolsTest extends EppTestCase {
.atTime("2001-06-08T00:00:00Z")
.hasResponse("poll_response_unrenew.xml");
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-8-TLD-23-24-2001"))
assertThatCommand("poll_ack.xml", ImmutableMap.of("ID", "1-8-TLD-19-20-2001"))
.atTime("2001-06-08T00:00:01Z")
.hasResponse("poll_ack_response_empty.xml");
@ -129,7 +129,7 @@ class EppLifecycleToolsTest extends EppTestCase {
.hasResponse(
"poll_response_autorenew.xml",
ImmutableMap.of(
"ID", "1-8-TLD-23-26-2003",
"ID", "1-8-TLD-19-22-2003",
"QDATE", "2003-06-01T00:02:00Z",
"DOMAIN", "example.tld",
"EXDATE", "2004-06-01T00:02:00Z"));

View file

@ -3,7 +3,7 @@
<result code="1301">
<msg>Command completed successfully; ack to dequeue</msg>
</result>
<msgQ count="1" id="1-8-TLD-23-24-2001">
<msgQ count="1" id="1-8-TLD-19-20-2001">
<qDate>2001-06-07T00:00:00Z</qDate>
<msg>Domain example.tld was unrenewed by 3 years; now expires at 2003-06-01T00:02:00.000Z.</msg>
</msgQ>

View file

@ -273,6 +273,7 @@ class google.registry.model.domain.DomainHistory {
java.lang.String clientId;
java.lang.String otherClientId;
java.lang.String reason;
java.util.Set<google.registry.model.domain.GracePeriod$GracePeriodHistory> gracePeriodHistories;
java.util.Set<google.registry.model.domain.secdns.DomainDsDataHistory> dsDataHistories;
java.util.Set<google.registry.model.reporting.DomainTransactionRecord> domainTransactionRecords;
org.joda.time.DateTime modificationTime;
@ -281,6 +282,17 @@ class google.registry.model.domain.GracePeriod {
google.registry.model.domain.rgp.GracePeriodStatus type;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$OneTime> billingEventOneTime;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> billingEventRecurring;
java.lang.Long gracePeriodId;
java.lang.String clientId;
org.joda.time.DateTime expirationTime;
}
class google.registry.model.domain.GracePeriod$GracePeriodHistory {
google.registry.model.domain.rgp.GracePeriodStatus type;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$OneTime> billingEventOneTime;
google.registry.persistence.VKey<google.registry.model.billing.BillingEvent$Recurring> billingEventRecurring;
java.lang.Long domainHistoryRevisionId;
java.lang.Long gracePeriodHistoryRevisionId;
java.lang.Long gracePeriodId;
java.lang.String clientId;
org.joda.time.DateTime expirationTime;
}