mirror of
https://github.com/google/nomulus.git
synced 2025-05-14 00:17:20 +02:00
Add syntheticCreationTime to BillingEvent.OneTime
In order to clean up potentially bad BillingEvent.Recurring expansions, we'll need to be able to trace synthetic billing events back to particular runs of the []. This field will be set to the cursor time at the start of the MR (all expansions in one MR job will have the same timestamp). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=121999938
This commit is contained in:
parent
d62da7bb19
commit
51362722cd
4 changed files with 76 additions and 18 deletions
|
@ -216,6 +216,15 @@ public abstract class BillingEvent extends ImmutableObject
|
||||||
@IgnoreSave(IfNull.class)
|
@IgnoreSave(IfNull.class)
|
||||||
Integer periodYears = null;
|
Integer periodYears = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For {@link Flag#SYNTHETIC} events, when this event was persisted to datastore (i.e. the
|
||||||
|
* cursor position at the time the recurrence expansion job was last run). In the event a job
|
||||||
|
* needs to be undone, a query on this field will return the complete set of potentially bad
|
||||||
|
* events.
|
||||||
|
*/
|
||||||
|
@Index
|
||||||
|
DateTime syntheticCreationTime;
|
||||||
|
|
||||||
public Money getCost() {
|
public Money getCost() {
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
@ -228,6 +237,10 @@ public abstract class BillingEvent extends ImmutableObject
|
||||||
return periodYears;
|
return periodYears;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DateTime getSyntheticCreationTime() {
|
||||||
|
return syntheticCreationTime;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder asBuilder() {
|
public Builder asBuilder() {
|
||||||
return new Builder(clone(this));
|
return new Builder(clone(this));
|
||||||
|
@ -259,6 +272,11 @@ public abstract class BillingEvent extends ImmutableObject
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setSyntheticCreationTime(DateTime syntheticCreationTime) {
|
||||||
|
getInstance().syntheticCreationTime = syntheticCreationTime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OneTime build() {
|
public OneTime build() {
|
||||||
OneTime instance = getInstance();
|
OneTime instance = getInstance();
|
||||||
|
@ -270,6 +288,10 @@ public abstract class BillingEvent extends ImmutableObject
|
||||||
checkState(
|
checkState(
|
||||||
reasonsWithPeriods.contains(instance.reason) == (instance.periodYears != null),
|
reasonsWithPeriods.contains(instance.reason) == (instance.periodYears != null),
|
||||||
"Period years must be set if and only if reason is CREATE, RENEW, or TRANSFER.");
|
"Period years must be set if and only if reason is CREATE, RENEW, or TRANSFER.");
|
||||||
|
checkState(
|
||||||
|
instance.getFlags().contains(Flag.SYNTHETIC)
|
||||||
|
== (instance.syntheticCreationTime != null),
|
||||||
|
"Billing events with SYNTHETIC flag set must have a synthetic creation time.");
|
||||||
return super.build();
|
return super.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||||
HistoryEntry historyEntry2;
|
HistoryEntry historyEntry2;
|
||||||
DomainResource domain;
|
DomainResource domain;
|
||||||
BillingEvent.OneTime oneTime;
|
BillingEvent.OneTime oneTime;
|
||||||
|
BillingEvent.OneTime oneTimeSynthetic;
|
||||||
BillingEvent.Recurring recurring;
|
BillingEvent.Recurring recurring;
|
||||||
BillingEvent.Cancellation cancellationOneTime;
|
BillingEvent.Cancellation cancellationOneTime;
|
||||||
BillingEvent.Cancellation cancellationRecurring;
|
BillingEvent.Cancellation cancellationRecurring;
|
||||||
|
@ -84,6 +85,16 @@ public class BillingEventTest extends EntityTestCase {
|
||||||
.setCost(Money.of(USD, 1))
|
.setCost(Money.of(USD, 1))
|
||||||
.setEventTime(now)
|
.setEventTime(now)
|
||||||
.setBillingTime(now.plusDays(5))));
|
.setBillingTime(now.plusDays(5))));
|
||||||
|
oneTimeSynthetic = persistResource(commonInit(
|
||||||
|
new BillingEvent.OneTime.Builder()
|
||||||
|
.setParent(historyEntry)
|
||||||
|
.setReason(Reason.CREATE)
|
||||||
|
.setFlags(ImmutableSet.of(BillingEvent.Flag.ANCHOR_TENANT, BillingEvent.Flag.SYNTHETIC))
|
||||||
|
.setSyntheticCreationTime(now.plusDays(10))
|
||||||
|
.setPeriodYears(2)
|
||||||
|
.setCost(Money.of(USD, 1))
|
||||||
|
.setEventTime(now)
|
||||||
|
.setBillingTime(now.plusDays(5))));
|
||||||
recurring = persistResource(commonInit(
|
recurring = persistResource(commonInit(
|
||||||
new BillingEvent.Recurring.Builder()
|
new BillingEvent.Recurring.Builder()
|
||||||
.setParent(historyEntry)
|
.setParent(historyEntry)
|
||||||
|
@ -136,7 +147,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||||
// Note that these are all tested separately because BillingEvent is an abstract base class that
|
// Note that these are all tested separately because BillingEvent is an abstract base class that
|
||||||
// lacks the @Entity annotation, and thus we cannot call .type(BillingEvent.class)
|
// lacks the @Entity annotation, and thus we cannot call .type(BillingEvent.class)
|
||||||
assertThat(ofy().load().type(BillingEvent.OneTime.class).ancestor(domain).list())
|
assertThat(ofy().load().type(BillingEvent.OneTime.class).ancestor(domain).list())
|
||||||
.containsExactly(oneTime);
|
.containsExactly(oneTime, oneTimeSynthetic);
|
||||||
assertThat(ofy().load().type(BillingEvent.Recurring.class).ancestor(domain).list())
|
assertThat(ofy().load().type(BillingEvent.Recurring.class).ancestor(domain).list())
|
||||||
.containsExactly(recurring);
|
.containsExactly(recurring);
|
||||||
assertThat(ofy().load().type(BillingEvent.Cancellation.class).ancestor(domain).list())
|
assertThat(ofy().load().type(BillingEvent.Cancellation.class).ancestor(domain).list())
|
||||||
|
@ -144,7 +155,7 @@ public class BillingEventTest extends EntityTestCase {
|
||||||
assertThat(ofy().load().type(BillingEvent.Modification.class).ancestor(domain).list())
|
assertThat(ofy().load().type(BillingEvent.Modification.class).ancestor(domain).list())
|
||||||
.containsExactly(modification);
|
.containsExactly(modification);
|
||||||
assertThat(ofy().load().type(BillingEvent.OneTime.class).ancestor(historyEntry).list())
|
assertThat(ofy().load().type(BillingEvent.OneTime.class).ancestor(historyEntry).list())
|
||||||
.containsExactly(oneTime);
|
.containsExactly(oneTime, oneTimeSynthetic);
|
||||||
assertThat(ofy().load().type(BillingEvent.Recurring.class).ancestor(historyEntry).list())
|
assertThat(ofy().load().type(BillingEvent.Recurring.class).ancestor(historyEntry).list())
|
||||||
.containsExactly(recurring);
|
.containsExactly(recurring);
|
||||||
assertThat(ofy().load().type(BillingEvent.Cancellation.class).ancestor(historyEntry2).list())
|
assertThat(ofy().load().type(BillingEvent.Cancellation.class).ancestor(historyEntry2).list())
|
||||||
|
@ -155,13 +166,35 @@ public class BillingEventTest extends EntityTestCase {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIndexing() throws Exception {
|
public void testIndexing() throws Exception {
|
||||||
verifyIndexing(oneTime, "clientId", "eventTime", "billingTime");
|
verifyIndexing(oneTime, "clientId", "eventTime", "billingTime", "syntheticCreationTime");
|
||||||
|
verifyIndexing(
|
||||||
|
oneTimeSynthetic, "clientId", "eventTime", "billingTime", "syntheticCreationTime");
|
||||||
verifyIndexing(
|
verifyIndexing(
|
||||||
recurring, "clientId", "eventTime", "recurrenceEndTime", "recurrenceTimeOfYear.timeString");
|
recurring, "clientId", "eventTime", "recurrenceEndTime", "recurrenceTimeOfYear.timeString");
|
||||||
verifyIndexing(cancellationOneTime, "clientId", "eventTime", "billingTime");
|
verifyIndexing(cancellationOneTime, "clientId", "eventTime", "billingTime");
|
||||||
verifyIndexing(modification, "clientId", "eventTime");
|
verifyIndexing(modification, "clientId", "eventTime");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailure_syntheticFlagWithoutCreationTime() {
|
||||||
|
thrown.expect(
|
||||||
|
IllegalStateException.class,
|
||||||
|
"Billing events with SYNTHETIC flag set must have a synthetic creation time");
|
||||||
|
oneTime.asBuilder()
|
||||||
|
.setFlags(ImmutableSet.of(BillingEvent.Flag.SYNTHETIC))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailure_syntheticCreationTimeWithoutFlag() {
|
||||||
|
thrown.expect(
|
||||||
|
IllegalStateException.class,
|
||||||
|
"Billing events with SYNTHETIC flag set must have a synthetic creation time");
|
||||||
|
oneTime.asBuilder()
|
||||||
|
.setSyntheticCreationTime(now.plusDays(10))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_cancellation_forGracePeriod_withOneTime() {
|
public void testSuccess_cancellation_forGracePeriod_withOneTime() {
|
||||||
BillingEvent.Cancellation newCancellation = BillingEvent.Cancellation.forGracePeriod(
|
BillingEvent.Cancellation newCancellation = BillingEvent.Cancellation.forGracePeriod(
|
||||||
|
|
|
@ -25,28 +25,28 @@ public class DeleteDomainCommandTest extends EppToolCommandTestCase<DeleteDomain
|
||||||
public void testSuccess() throws Exception {
|
public void testSuccess() throws Exception {
|
||||||
runCommand("--client=NewRegistrar", "--domain_name=example.tld", "--force",
|
runCommand("--client=NewRegistrar", "--domain_name=example.tld", "--force",
|
||||||
"--reason=Test");
|
"--reason=Test");
|
||||||
new EppVerifier().verifySent("testdata/domain_delete.xml");
|
eppVerifier().verifySent("testdata/domain_delete.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_multipleWordReason() throws Exception {
|
public void testSuccess_multipleWordReason() throws Exception {
|
||||||
runCommand("--client=NewRegistrar", "--domain_name=example.tld", "--force",
|
runCommand("--client=NewRegistrar", "--domain_name=example.tld", "--force",
|
||||||
"--reason=\"Test test\"");
|
"--reason=\"Test test\"");
|
||||||
new EppVerifier().verifySent("testdata/domain_delete_multiple_word_reason.xml");
|
eppVerifier().verifySent("testdata/domain_delete_multiple_word_reason.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_requestedByRegistrarFalse() throws Exception {
|
public void testSuccess_requestedByRegistrarFalse() throws Exception {
|
||||||
runCommand("--client=NewRegistrar", "--domain_name=example.tld", "--force",
|
runCommand("--client=NewRegistrar", "--domain_name=example.tld", "--force",
|
||||||
"--reason=Test", "--registrar_request=false");
|
"--reason=Test", "--registrar_request=false");
|
||||||
new EppVerifier().verifySent("testdata/domain_delete.xml");
|
eppVerifier().verifySent("testdata/domain_delete.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_requestedByRegistrarTrue() throws Exception {
|
public void testSuccess_requestedByRegistrarTrue() throws Exception {
|
||||||
runCommand("--client=NewRegistrar", "--domain_name=example.tld", "--force",
|
runCommand("--client=NewRegistrar", "--domain_name=example.tld", "--force",
|
||||||
"--reason=Test", "--registrar_request=true");
|
"--reason=Test", "--registrar_request=true");
|
||||||
new EppVerifier().verifySent("testdata/domain_delete_by_registrar.xml");
|
eppVerifier().verifySent("testdata/domain_delete_by_registrar.xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -67,29 +67,32 @@ public abstract class EppToolCommandTestCase<C extends EppToolCommand> extends C
|
||||||
|
|
||||||
/** Helper to get a new {@link EppVerifier} instance. */
|
/** Helper to get a new {@link EppVerifier} instance. */
|
||||||
EppVerifier eppVerifier() {
|
EppVerifier eppVerifier() {
|
||||||
return new EppVerifier();
|
return new EppVerifier("NewRegistrar", false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Builder pattern class for verifying EPP commands sent to the server. */
|
/** Class for verifying EPP commands sent to the server. */
|
||||||
class EppVerifier {
|
class EppVerifier {
|
||||||
|
|
||||||
String clientIdentifier = "NewRegistrar";
|
private final String clientIdentifier;
|
||||||
boolean superuser = false;
|
private final boolean superuser;
|
||||||
boolean dryRun = false;
|
private final boolean dryRun;
|
||||||
|
|
||||||
|
private EppVerifier(String clientIdentifier, boolean superuser, boolean dryRun) {
|
||||||
|
this.clientIdentifier = clientIdentifier;
|
||||||
|
this.superuser = superuser;
|
||||||
|
this.dryRun = dryRun;
|
||||||
|
}
|
||||||
|
|
||||||
EppVerifier setClientIdentifier(String clientIdentifier) {
|
EppVerifier setClientIdentifier(String clientIdentifier) {
|
||||||
this.clientIdentifier = clientIdentifier;
|
return new EppVerifier(clientIdentifier, superuser, dryRun);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EppVerifier asSuperuser() {
|
EppVerifier asSuperuser() {
|
||||||
this.superuser = true;
|
return new EppVerifier(clientIdentifier, true, dryRun);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EppVerifier asDryRun() {
|
EppVerifier asDryRun() {
|
||||||
this.dryRun = true;
|
return new EppVerifier(clientIdentifier, superuser, true);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void verifySent(String... filesToMatch) throws Exception {
|
void verifySent(String... filesToMatch) throws Exception {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue