mirror of
https://github.com/google/nomulus
synced 2026-09-19 06:32:00 +00:00
Add new columns to BillingEvent (#1573)
* Add new columns to BillingEvent.java * Improve PR and modifyJodaMoneyType to handle null currency in override * Add test cases for edge cases of nullSafeGet in JodaMoneyType * Improve assertions
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
package google.registry.model.billing;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
@@ -36,6 +37,7 @@ import com.googlecode.objectify.Key;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
@@ -49,6 +51,7 @@ import google.registry.testing.TestOfyAndSql;
|
||||
import google.registry.testing.TestOfyOnly;
|
||||
import google.registry.testing.TestSqlOnly;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.math.BigDecimal;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -474,4 +477,487 @@ public class BillingEventTest extends EntityTestCase {
|
||||
.setParent(domainHistory)
|
||||
.build();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_defaultRenewalPriceBehavior_assertsIsDefault() {
|
||||
assertThat(recurring.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.DEFAULT);
|
||||
assertThat(recurring.getRenewalPrice()).isEmpty();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_getRenewalPriceBehavior_returnsRightBehavior() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.NONPREMIUM);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_setRenewalPriceBehaviorThenBuild_defaultToSpecified() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.DEFAULT);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
persistResource(
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPrice(Money.of(USD, 100))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.build());
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPriceBehavior())
|
||||
.isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_setRenewalPriceBehaviorThenBuild_defaultToNonPremium() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.DEFAULT);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
persistResource(
|
||||
loadedEntity.asBuilder().setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM).build());
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPriceBehavior())
|
||||
.isEqualTo(RenewalPriceBehavior.NONPREMIUM);
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPrice()).isEmpty();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_setRenewalPriceBehaviorThenBuild_nonPremiumToSpecified() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.NONPREMIUM);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
persistResource(
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPrice(Money.of(USD, 100))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.build());
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPriceBehavior())
|
||||
.isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_setRenewalPriceBehaviorThenBuild_nonPremiumToDefault() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.NONPREMIUM);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
persistResource(
|
||||
loadedEntity.asBuilder().setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT).build());
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPriceBehavior())
|
||||
.isEqualTo(RenewalPriceBehavior.DEFAULT);
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPrice()).isEmpty();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_setRenewalPriceBehaviorThenBuild_specifiedToDefault() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, 100))
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(recurringEvent.getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
persistResource(
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPrice(null)
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT)
|
||||
.build());
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPriceBehavior())
|
||||
.isEqualTo(RenewalPriceBehavior.DEFAULT);
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPrice()).isEmpty();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_setRenewalPriceBehaviorThenBuild_specifiedToNonPremium() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, 100))
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(recurringEvent.getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
persistResource(
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPrice(null)
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.build());
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPriceBehavior())
|
||||
.isEqualTo(RenewalPriceBehavior.NONPREMIUM);
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPrice()).isEmpty();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_setRenewalPriceBehaviorThenBuild_defaultToSpecified_needRenewalPrice() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.DEFAULT);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_setRenewalPriceBehaviorThenBuild_defaultToPremium_noNeedToAddRenewalPrice() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.DEFAULT);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.setRenewalPrice(Money.of(USD, 100))
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_setRenewalPriceBehaviorThenBuild_nonPremiumToDefault_noNeedToAddRenewalPrice() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.NONPREMIUM);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT)
|
||||
.setRenewalPrice(Money.of(USD, 100))
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_setRenewalPriceBehaviorThenBuild_nonPremiumToSpecified_needRenewalPrice() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.NONPREMIUM);
|
||||
assertThat(recurringEvent.getRenewalPrice()).isEmpty();
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_setRenewalPriceBehaviorThenBuild_specifiedToNonPremium_removeRenewalPrice() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, 100))
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(recurringEvent.getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_setRenewalPriceBehaviorThenBuild_specifiedToDefault_removeRenewalPrice() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, 100))
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(recurringEvent.getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
BillingEvent.Recurring loadedEntity = loadByEntity(recurringEvent);
|
||||
assertThat(loadedEntity).isEqualTo(recurringEvent);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
loadedEntity
|
||||
.asBuilder()
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT)
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_buildWithDefaultRenewalBehavior() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, BigDecimal.valueOf(100)))
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(recurringEvent.getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_buildWithNonPremiumRenewalBehavior() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.NONPREMIUM);
|
||||
assertThat(loadByEntity(recurringEvent).getRenewalPrice()).isEmpty();
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_buildWithSpecifiedRenewalBehavior() {
|
||||
BillingEvent.Recurring recurringEvent =
|
||||
persistResource(
|
||||
commonInit(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, BigDecimal.valueOf(100)))
|
||||
.setRecurrenceEndTime(END_OF_TIME)));
|
||||
assertThat(recurringEvent.getRenewalPriceBehavior()).isEqualTo(RenewalPriceBehavior.SPECIFIED);
|
||||
assertThat(recurringEvent.getRenewalPrice()).hasValue(Money.of(USD, 100));
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_buildWithSpecifiedRenewalBehavior_requiresNonNullRenewalPrice() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_buildWithNonPremiumRenewalBehavior_requiresNullRenewalPrice() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.NONPREMIUM)
|
||||
.setRenewalPrice(Money.of(USD, BigDecimal.valueOf(100)))
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testFailure_buildWithDefaultRenewalBehavior_requiresNullRenewalPrice() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(domainHistory)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setReason(Reason.RENEW)
|
||||
.setEventTime(now.plusYears(1))
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.DEFAULT)
|
||||
.setRenewalPrice(Money.of(USD, BigDecimal.valueOf(100)))
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.build());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"Renewal price can have a value if and only if the "
|
||||
+ "renewal price behavior is SPECIFIED");
|
||||
}
|
||||
}
|
||||
|
||||
+126
-4
@@ -16,6 +16,7 @@ package google.registry.persistence.converter;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.DatabaseHelper.insertInDb;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.ImmutableObject;
|
||||
@@ -23,6 +24,7 @@ import google.registry.model.replay.EntityTest.EntityForTesting;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaUnitTestExtension;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -34,9 +36,11 @@ import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.PersistenceException;
|
||||
import org.hibernate.annotations.Columns;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.IllegalCurrencyException;
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
@@ -65,7 +69,7 @@ public class JodaMoneyConverterTest {
|
||||
.createNativeQuery(
|
||||
"SELECT amount, currency FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getResultList());
|
||||
assertThat(result.size()).isEqualTo(1);
|
||||
assertThat(result).hasSize(1);
|
||||
// The amount property, when loaded as a raw value, has the same scale as the table column,
|
||||
// which is 2.
|
||||
assertThat(Arrays.asList((Object[]) result.get(0)))
|
||||
@@ -91,7 +95,7 @@ public class JodaMoneyConverterTest {
|
||||
.createNativeQuery(
|
||||
"SELECT amount, currency FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getResultList());
|
||||
assertThat(result.size()).isEqualTo(1);
|
||||
assertThat(result).hasSize(1);
|
||||
/* The amount property, when loaded as a raw value, has the same scale as the table column,
|
||||
which is 2. */
|
||||
assertThat(Arrays.asList((Object[]) result.get(0)))
|
||||
@@ -136,7 +140,7 @@ public class JodaMoneyConverterTest {
|
||||
"SELECT my_amount, my_currency, your_amount, your_currency FROM"
|
||||
+ " \"ComplexTestEntity\" WHERE name = 'id'")
|
||||
.getResultList());
|
||||
assertThat(result.size()).isEqualTo(1);
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(Arrays.asList((Object[]) result.get(0)))
|
||||
.containsExactly(
|
||||
BigDecimal.valueOf(100).setScale(2), "USD", BigDecimal.valueOf(80).setScale(2), "GBP")
|
||||
@@ -153,7 +157,7 @@ public class JodaMoneyConverterTest {
|
||||
.getResultList());
|
||||
ComplexTestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(ComplexTestEntity.class, "id"));
|
||||
assertThat(result.size()).isEqualTo(1);
|
||||
assertThat(result).hasSize(1);
|
||||
|
||||
assertThat(Arrays.asList((Object[]) result.get(0)))
|
||||
.containsExactly(BigDecimal.valueOf(2000).setScale(2), "JPY")
|
||||
@@ -164,6 +168,124 @@ public class JodaMoneyConverterTest {
|
||||
assertThat(persisted.moneyMap).containsExactlyEntriesIn(moneyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implicit test cases for @override method @nullSafeGet when constructing {@link Money} object
|
||||
* with null/invalid column(s).
|
||||
*/
|
||||
@Test
|
||||
void testNullSafeGet_nullAmountNullCurrency_returnsNull() throws SQLException {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
"INSERT INTO \"TestEntity\" (name, amount, currency) VALUES('id', null,"
|
||||
+ " null)")
|
||||
.executeUpdate());
|
||||
List<?> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
"SELECT amount, currency FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getResultList());
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(Arrays.asList((Object[]) result.get(0))).containsExactly(null, null).inOrder();
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery("SELECT money FROM TestEntity WHERE name = 'id'")
|
||||
.getResultList())
|
||||
.get(0))
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullSafeGet_nullAMountValidCurrency_throwsHibernateException() throws SQLException {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
"INSERT INTO \"TestEntity\" (name, amount, currency) VALUES('id', null,"
|
||||
+ " 'USD')")
|
||||
.executeUpdate());
|
||||
List<?> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
"SELECT amount, currency FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getResultList());
|
||||
assertThat(Arrays.asList((Object[]) result.get(0))).containsExactly(null, "USD");
|
||||
// CurrencyUnit.of() throws HibernateException for invalid currency which leads to persistance
|
||||
// error
|
||||
PersistenceException thrown =
|
||||
assertThrows(
|
||||
PersistenceException.class,
|
||||
() ->
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery("SELECT money FROM TestEntity WHERE name = 'id'")
|
||||
.getResultList()));
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"org.hibernate.HibernateException: Mismatching null state between currency 'USD' and"
|
||||
+ " amount 'null'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullSafeGet_nullAMountInValidCurrency_throwsIllegalCurrencyException()
|
||||
throws SQLException {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
"INSERT INTO \"TestEntity\" (name, amount, currency) VALUES('id', 100,"
|
||||
+ " 'INVALIDCURRENCY')")
|
||||
.executeUpdate());
|
||||
List<?> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
"SELECT amount, currency FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getResultList());
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(Arrays.asList((Object[]) result.get(0)))
|
||||
.containsExactly(BigDecimal.valueOf(100).setScale(2), "INVALIDCURRENCY")
|
||||
.inOrder();
|
||||
IllegalCurrencyException thrown =
|
||||
assertThrows(
|
||||
IllegalCurrencyException.class,
|
||||
() ->
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery("SELECT money FROM TestEntity WHERE name = 'id'")
|
||||
.getResultList()));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Unknown currency 'INVALIDCURRENCY'");
|
||||
}
|
||||
|
||||
// Override entity name to exclude outer-class name in table name. Not necessary if class is not
|
||||
// inner class.
|
||||
@Entity(name = "TestEntity")
|
||||
|
||||
@@ -65,13 +65,20 @@ class google.registry.model.billing.BillingEvent$Recurring {
|
||||
@Id java.lang.Long id;
|
||||
@Parent com.googlecode.objectify.Key<google.registry.model.domain.DomainHistory> parent;
|
||||
google.registry.model.billing.BillingEvent$Reason reason;
|
||||
google.registry.model.billing.BillingEvent$RenewalPriceBehavior renewalPriceBehavior;
|
||||
google.registry.model.common.TimeOfYear recurrenceTimeOfYear;
|
||||
java.lang.String clientId;
|
||||
java.lang.String targetId;
|
||||
java.util.Set<google.registry.model.billing.BillingEvent$Flag> flags;
|
||||
org.joda.money.Money renewalPrice;
|
||||
org.joda.time.DateTime eventTime;
|
||||
org.joda.time.DateTime recurrenceEndTime;
|
||||
}
|
||||
enum google.registry.model.billing.BillingEvent$RenewalPriceBehavior {
|
||||
DEFAULT;
|
||||
NONPREMIUM;
|
||||
SPECIFIED;
|
||||
}
|
||||
class google.registry.model.common.Cursor {
|
||||
@Id java.lang.String id;
|
||||
@Parent com.googlecode.objectify.Key<google.registry.model.common.EntityGroupRoot> parent;
|
||||
|
||||
Reference in New Issue
Block a user