mirror of
https://github.com/google/nomulus.git
synced 2025-07-01 08:43:34 +02:00
Use new renew cost calculation in handleFeeRequest() (#1694)
* Resolve conflict * Fix setup for existing test cases in info and check flow * Revise info flow test cases * Fix lint * Merge branch 'master' into handlefeerequest-renew * Address code review comments myself * Merge branch 'master' into handlefeerequest-renew * Get test passing * Add check flow tests * Format, consolidate test helpers * Don't unnecessarily specify XML name
This commit is contained in:
parent
d5c65bf8d7
commit
bda8961ea7
8 changed files with 349 additions and 41 deletions
|
@ -17,6 +17,7 @@ package google.registry.flows.domain;
|
|||
import static com.google.common.base.Strings.emptyToNull;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
|
||||
|
@ -31,6 +32,7 @@ import static google.registry.flows.domain.DomainFlowUtils.validateDomainNameWit
|
|||
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPredelegation;
|
||||
import static google.registry.model.tld.Registry.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.model.tld.label.ReservationType.getTypeOfHighestSeverity;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
@ -51,6 +53,7 @@ import google.registry.flows.custom.DomainCheckFlowCustomLogic.BeforeResponseRet
|
|||
import google.registry.flows.domain.token.AllocationTokenDomainCheckResults;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainCommand.Check;
|
||||
import google.registry.model.domain.fee.FeeCheckCommandExtension;
|
||||
|
@ -261,22 +264,26 @@ public final class DomainCheckFlow implements Flow {
|
|||
FeeCheckCommandExtension<?, ?> feeCheck = feeCheckOpt.get();
|
||||
ImmutableList.Builder<FeeCheckResponseExtensionItem> responseItems =
|
||||
new ImmutableList.Builder<>();
|
||||
ImmutableMap<String, EppResource> domainObjs =
|
||||
ImmutableMap<String, DomainBase> domainObjs =
|
||||
loadDomainsForRestoreChecks(feeCheck, domainNames, existingDomains);
|
||||
ImmutableMap<String, BillingEvent.Recurring> recurrences =
|
||||
loadRecurrencesForDomains(domainObjs);
|
||||
|
||||
for (FeeCheckCommandExtensionItem feeCheckItem : feeCheck.getItems()) {
|
||||
for (String domainName : getDomainNamesToCheckForFee(feeCheckItem, domainNames.keySet())) {
|
||||
FeeCheckResponseExtensionItem.Builder<?> builder = feeCheckItem.createResponseBuilder();
|
||||
Optional<DomainBase> domainBase = Optional.ofNullable(domainObjs.get(domainName));
|
||||
handleFeeRequest(
|
||||
feeCheckItem,
|
||||
builder,
|
||||
domainNames.get(domainName),
|
||||
Optional.ofNullable((DomainBase) domainObjs.get(domainName)),
|
||||
domainBase,
|
||||
feeCheck.getCurrency(),
|
||||
now,
|
||||
pricingLogic,
|
||||
allocationToken,
|
||||
availableDomains.contains(domainName));
|
||||
availableDomains.contains(domainName),
|
||||
recurrences.getOrDefault(domainName, null));
|
||||
responseItems.add(builder.setDomainNameIfSupported(domainName).build());
|
||||
}
|
||||
}
|
||||
|
@ -294,7 +301,7 @@ public final class DomainCheckFlow implements Flow {
|
|||
* nicer in Cloud SQL when we can SELECT just the fields we want rather than having to load the
|
||||
* entire entity.
|
||||
*/
|
||||
private ImmutableMap<String, EppResource> loadDomainsForRestoreChecks(
|
||||
private ImmutableMap<String, DomainBase> loadDomainsForRestoreChecks(
|
||||
FeeCheckCommandExtension<?, ?> feeCheck,
|
||||
ImmutableMap<String, InternetDomainName> domainNames,
|
||||
ImmutableMap<String, ForeignKeyIndex<DomainBase>> existingDomains) {
|
||||
|
@ -326,7 +333,23 @@ public final class DomainCheckFlow implements Flow {
|
|||
ImmutableMap<VKey<? extends EppResource>, EppResource> loadedDomains =
|
||||
EppResource.loadCached(ImmutableList.copyOf(existingDomainsToLoad.values()));
|
||||
return ImmutableMap.copyOf(
|
||||
Maps.transformEntries(existingDomainsToLoad, (k, v) -> loadedDomains.get(v)));
|
||||
Maps.transformEntries(existingDomainsToLoad, (k, v) -> (DomainBase) loadedDomains.get(v)));
|
||||
}
|
||||
|
||||
private ImmutableMap<String, BillingEvent.Recurring> loadRecurrencesForDomains(
|
||||
ImmutableMap<String, DomainBase> domainObjs) {
|
||||
return tm().transact(
|
||||
() -> {
|
||||
ImmutableMap<VKey<? extends BillingEvent.Recurring>, BillingEvent.Recurring>
|
||||
recurrences =
|
||||
tm().loadByKeys(
|
||||
domainObjs.values().stream()
|
||||
.map(DomainBase::getAutorenewBillingEvent)
|
||||
.collect(toImmutableSet()));
|
||||
return ImmutableMap.copyOf(
|
||||
Maps.transformValues(
|
||||
domainObjs, d -> recurrences.get(d.getAutorenewBillingEvent())));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -633,7 +633,8 @@ public class DomainFlowUtils {
|
|||
DateTime currentDate,
|
||||
DomainPricingLogic pricingLogic,
|
||||
Optional<AllocationToken> allocationToken,
|
||||
boolean isAvailable)
|
||||
boolean isAvailable,
|
||||
@Nullable Recurring recurringBillingEvent)
|
||||
throws EppException {
|
||||
DateTime now = currentDate;
|
||||
// Use the custom effective date specified in the fee check request, if there is one.
|
||||
|
@ -680,7 +681,10 @@ public class DomainFlowUtils {
|
|||
break;
|
||||
case RENEW:
|
||||
builder.setAvailIfSupported(true);
|
||||
fees = pricingLogic.getRenewPrice(registry, domainNameString, now, years, null).getFees();
|
||||
fees =
|
||||
pricingLogic
|
||||
.getRenewPrice(registry, domainNameString, now, years, recurringBillingEvent)
|
||||
.getFees();
|
||||
break;
|
||||
case RESTORE:
|
||||
// The minimum allowable period per the EPP spec is 1, so, strangely, 1 year still has to be
|
||||
|
|
|
@ -163,7 +163,8 @@ public final class DomainInfoFlow implements Flow {
|
|||
now,
|
||||
pricingLogic,
|
||||
Optional.empty(),
|
||||
false);
|
||||
false,
|
||||
tm().transact(() -> tm().loadByKey(domain.getAutorenewBillingEvent())));
|
||||
extensions.add(builder.build());
|
||||
}
|
||||
return extensions.build();
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
package google.registry.flows.domain;
|
||||
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.DEFAULT;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.NONPREMIUM;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.SPECIFIED;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.eppoutput.CheckData.DomainCheck.create;
|
||||
|
@ -24,6 +27,7 @@ import static google.registry.testing.DatabaseHelper.createTlds;
|
|||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.newDomainBase;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistBillingRecurrenceForDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistPremiumList;
|
||||
import static google.registry.testing.DatabaseHelper.persistReservedList;
|
||||
|
@ -66,7 +70,11 @@ import google.registry.flows.domain.DomainFlowUtils.TrailingDashException;
|
|||
import google.registry.flows.domain.DomainFlowUtils.TransfersAreAlwaysForOneYearException;
|
||||
import google.registry.flows.domain.DomainFlowUtils.UnknownFeeCommandException;
|
||||
import google.registry.flows.exceptions.TooManyResourceChecksException;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
|
@ -75,6 +83,7 @@ import google.registry.model.tld.Registry;
|
|||
import google.registry.model.tld.Registry.TldState;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.testing.SetClockExtension;
|
||||
import java.math.BigDecimal;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -806,6 +815,29 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
|||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v06.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_existingPremiumDomain_withNonPremiumRenewalBehavior() throws Exception {
|
||||
createTld("example");
|
||||
persistBillingRecurrenceForDomain(persistActiveDomain("rich.example"), NONPREMIUM, null);
|
||||
setEppInput("domain_check_fee_premium_v06.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_check_fee_response_domain_exists_v06.xml",
|
||||
ImmutableMap.of("RENEWPRICE", "11.00")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_existingPremiumDomain_withSpecifiedRenewalBehavior() throws Exception {
|
||||
createTld("example");
|
||||
persistBillingRecurrenceForDomain(
|
||||
persistActiveDomain("rich.example"), SPECIFIED, Money.of(USD, new BigDecimal("15.55")));
|
||||
setEppInput("domain_check_fee_premium_v06.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_check_fee_response_domain_exists_v06.xml",
|
||||
ImmutableMap.of("RENEWPRICE", "15.55")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_premium_eap_v06() throws Exception {
|
||||
createTld("example");
|
||||
|
@ -829,21 +861,28 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
|||
@Test
|
||||
void testFeeExtension_premium_eap_v06_withRenewalOnRestore() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v06.xml");
|
||||
clock.setTo(DateTime.parse("2010-01-01T10:00:00Z"));
|
||||
DateTime startTime = DateTime.parse("2010-01-01T10:00:00Z");
|
||||
clock.setTo(startTime);
|
||||
persistResource(
|
||||
persistActiveDomain("rich.example")
|
||||
.asBuilder()
|
||||
.setDeletionTime(clock.nowUtc().plusDays(25))
|
||||
.setRegistrationExpirationTime(clock.nowUtc().minusDays(1))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.build());
|
||||
persistPendingDeleteDomain("rich.example");
|
||||
setEppInput("domain_check_fee_premium_v06.xml");
|
||||
persistResource(
|
||||
Registry.get("example")
|
||||
.asBuilder()
|
||||
.setEapFeeSchedule(
|
||||
new ImmutableSortedMap.Builder<DateTime, Money>(Ordering.natural())
|
||||
.put(START_OF_TIME, Money.of(USD, 0))
|
||||
.put(clock.nowUtc().minusDays(1), Money.of(USD, 100))
|
||||
.put(clock.nowUtc().plusDays(1), Money.of(USD, 50))
|
||||
.put(clock.nowUtc().plusDays(2), Money.of(USD, 0))
|
||||
.put(startTime.minusDays(1), Money.of(USD, 100))
|
||||
.put(startTime.plusDays(1), Money.of(USD, 50))
|
||||
.put(startTime.plusDays(2), Money.of(USD, 0))
|
||||
.build())
|
||||
.build());
|
||||
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_eap_response_v06_with_renewal.xml"));
|
||||
}
|
||||
|
||||
|
@ -942,7 +981,7 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
|||
.setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70"))
|
||||
.build());
|
||||
// The domain needs to exist in order for it to be loaded to check for restore fee.
|
||||
persistActiveDomain("allowedinsunrise.tld");
|
||||
persistBillingRecurrenceForDomain(persistActiveDomain("allowedinsunrise.tld"), DEFAULT, null);
|
||||
setEppInput("domain_check_fee_reserved_dupes_v06.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_dupes_v06.xml"));
|
||||
}
|
||||
|
@ -1034,8 +1073,8 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
|||
.setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70"))
|
||||
.build());
|
||||
// The domain needs to exist in order for it to be loaded to check for restore fee.
|
||||
persistActiveDomain("allowedinsunrise.tld");
|
||||
setEppInput("domain_check_fee_reserved_dupes_v12.xml");
|
||||
persistBillingRecurrenceForDomain(persistActiveDomain("allowedinsunrise.tld"), DEFAULT, null);
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_dupes_response_v12.xml"));
|
||||
}
|
||||
|
||||
|
@ -1375,7 +1414,8 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
|||
assertTldsFieldLogged("com", "net", "org");
|
||||
}
|
||||
|
||||
private void persistPendingDeleteDomain(String domainName) {
|
||||
private DomainBase persistPendingDeleteDomain(String domainName) {
|
||||
DomainBase existingDomain =
|
||||
persistResource(
|
||||
newDomainBase(domainName)
|
||||
.asBuilder()
|
||||
|
@ -1383,5 +1423,26 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
|||
.setRegistrationExpirationTime(clock.nowUtc().minusDays(1))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.build());
|
||||
DomainHistory historyEntry =
|
||||
persistResource(
|
||||
new DomainHistory.Builder()
|
||||
.setDomain(existingDomain)
|
||||
.setType(HistoryEntry.Type.DOMAIN_DELETE)
|
||||
.setModificationTime(existingDomain.getCreationTime())
|
||||
.setRegistrarId(existingDomain.getCreationRegistrarId())
|
||||
.build());
|
||||
BillingEvent.Recurring renewEvent =
|
||||
persistResource(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setReason(Reason.RENEW)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(existingDomain.getDomainName())
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(existingDomain.getCreationTime())
|
||||
.setRecurrenceEndTime(clock.nowUtc())
|
||||
.setParent(historyEntry)
|
||||
.build());
|
||||
return persistResource(
|
||||
existingDomain.asBuilder().setAutorenewBillingEvent(renewEvent.createVKey()).build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,17 +16,23 @@ package google.registry.flows.domain;
|
|||
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.DEFAULT;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.NONPREMIUM;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.SPECIFIED;
|
||||
import static google.registry.model.tld.Registry.TldState.QUIET_PERIOD;
|
||||
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.newDomainBase;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistBillingRecurrenceForDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistPremiumList;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.TestDataHelper.updateSubstitutions;
|
||||
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.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
@ -46,6 +52,7 @@ import google.registry.flows.domain.DomainFlowUtils.TransfersAreAlwaysForOneYear
|
|||
import google.registry.model.billing.BillingEvent;
|
||||
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.contact.ContactAuthInfo;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
|
@ -64,6 +71,8 @@ import google.registry.model.tld.Registry;
|
|||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.SetClockExtension;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Order;
|
||||
|
@ -175,12 +184,6 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
}
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(
|
||||
String expectedXmlFilename, boolean inactive, ImmutableMap<String, String> substitutions)
|
||||
throws Exception {
|
||||
doSuccessfulTest(expectedXmlFilename, inactive, substitutions, false);
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(String expectedXmlFilename, boolean inactive) throws Exception {
|
||||
doSuccessfulTest(expectedXmlFilename, inactive, ImmutableMap.of(), false);
|
||||
}
|
||||
|
@ -195,6 +198,16 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
doSuccessfulTest(expectedXmlFilename, true);
|
||||
}
|
||||
|
||||
/** sets up a sample recurring billing event as part of the domain creation process. */
|
||||
private void setUpBillingEventForExistingDomain() {
|
||||
setUpBillingEventForExistingDomain(DEFAULT, null);
|
||||
}
|
||||
|
||||
private void setUpBillingEventForExistingDomain(
|
||||
RenewalPriceBehavior renewalPriceBehavior, @Nullable Money renewalPrice) {
|
||||
domain = persistBillingRecurrenceForDomain(domain, renewalPriceBehavior, renewalPrice);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotLoggedIn() {
|
||||
sessionMetadata.setRegistrarId(null);
|
||||
|
@ -685,6 +698,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "create",
|
||||
"PERIOD", "2"));
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_response.xml",
|
||||
false,
|
||||
|
@ -692,7 +706,8 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "create",
|
||||
"DESCRIPTION", "create",
|
||||
"PERIOD", "2",
|
||||
"FEE", "26.00"));
|
||||
"FEE", "26.00"),
|
||||
true);
|
||||
}
|
||||
|
||||
/** Test renew command. */
|
||||
|
@ -705,6 +720,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "renew",
|
||||
"PERIOD", "2"));
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_response.xml",
|
||||
false,
|
||||
|
@ -712,7 +728,8 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "renew",
|
||||
"DESCRIPTION", "renew",
|
||||
"PERIOD", "2",
|
||||
"FEE", "22.00"));
|
||||
"FEE", "22.00"),
|
||||
true);
|
||||
}
|
||||
|
||||
/** Test transfer command. */
|
||||
|
@ -725,6 +742,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "transfer",
|
||||
"PERIOD", "1"));
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_response.xml",
|
||||
false,
|
||||
|
@ -732,7 +750,8 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "transfer",
|
||||
"DESCRIPTION", "renew",
|
||||
"PERIOD", "1",
|
||||
"FEE", "11.00"));
|
||||
"FEE", "11.00"),
|
||||
true);
|
||||
}
|
||||
|
||||
/** Test restore command. */
|
||||
|
@ -745,7 +764,8 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "restore",
|
||||
"PERIOD", "1"));
|
||||
persistTestEntities(false);
|
||||
doSuccessfulTest("domain_info_fee_restore_response.xml", false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
doSuccessfulTest("domain_info_fee_restore_response.xml", false, ImmutableMap.of(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -754,13 +774,15 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"domain_info_fee.xml",
|
||||
updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "restore", "PERIOD", "1"));
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
persistResource(
|
||||
domain
|
||||
.asBuilder()
|
||||
.setDeletionTime(clock.nowUtc().plusDays(25))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.build());
|
||||
doSuccessfulTest("domain_info_fee_restore_response_no_renewal.xml", false);
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_restore_response_no_renewal.xml", false, ImmutableMap.of(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -771,6 +793,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
updateSubstitutions(
|
||||
SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "restore", "PERIOD", "1"));
|
||||
persistTestEntities("rich.example", false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
persistResource(
|
||||
domain
|
||||
.asBuilder()
|
||||
|
@ -778,7 +801,8 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
.setRegistrationExpirationTime(clock.nowUtc().minusDays(1))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.build());
|
||||
doSuccessfulTest("domain_info_fee_restore_response_with_renewal.xml", false);
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_restore_response_with_renewal.xml", false, ImmutableMap.of(), true);
|
||||
}
|
||||
|
||||
/** Test create command on a premium label. */
|
||||
|
@ -793,10 +817,12 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "create",
|
||||
"PERIOD", "1"));
|
||||
persistTestEntities("rich.example", false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_premium_response.xml",
|
||||
false,
|
||||
ImmutableMap.of("COMMAND", "create", "DESCRIPTION", "create"));
|
||||
ImmutableMap.of("COMMAND", "create", "DESCRIPTION", "create"),
|
||||
true);
|
||||
}
|
||||
|
||||
/** Test renew command on a premium label. */
|
||||
|
@ -811,10 +837,107 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "renew",
|
||||
"PERIOD", "1"));
|
||||
persistTestEntities("rich.example", false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_premium_response.xml",
|
||||
false,
|
||||
ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew"));
|
||||
ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew"),
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_renewCommandPremium_anchorTenant() throws Exception {
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setPremiumList(persistPremiumList("tld", USD, "example,USD 70"))
|
||||
.build());
|
||||
setEppInput(
|
||||
"domain_info_fee.xml",
|
||||
updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "renew", "PERIOD", "1"));
|
||||
persistTestEntities("example.tld", false);
|
||||
setUpBillingEventForExistingDomain(NONPREMIUM, null);
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_response.xml",
|
||||
false,
|
||||
ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew", "FEE", "11.0", "PERIOD", "1"),
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_renewCommandPremium_internalRegistration() throws Exception {
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setPremiumList(persistPremiumList("tld", USD, "example,USD 70"))
|
||||
.build());
|
||||
setEppInput(
|
||||
"domain_info_fee.xml",
|
||||
updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "renew", "PERIOD", "1"));
|
||||
persistTestEntities("example.tld", false);
|
||||
setUpBillingEventForExistingDomain(SPECIFIED, Money.of(USD, 3));
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_response.xml",
|
||||
false,
|
||||
ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew", "FEE", "3.0", "PERIOD", "1"),
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_renewCommandPremium_anchorTenant_multiYear() throws Exception {
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setPremiumList(persistPremiumList("tld", USD, "example,USD 70"))
|
||||
.build());
|
||||
setEppInput(
|
||||
"domain_info_fee.xml",
|
||||
updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "renew", "PERIOD", "3"));
|
||||
persistTestEntities("example.tld", false);
|
||||
setUpBillingEventForExistingDomain(NONPREMIUM, null);
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_response.xml",
|
||||
false,
|
||||
ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew", "FEE", "33.0", "PERIOD", "3"),
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_renewCommandPremium_internalRegistration_multiYear() throws Exception {
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setPremiumList(persistPremiumList("tld", USD, "example,USD 70"))
|
||||
.build());
|
||||
setEppInput(
|
||||
"domain_info_fee.xml",
|
||||
updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "renew", "PERIOD", "3"));
|
||||
persistTestEntities("example.tld", false);
|
||||
setUpBillingEventForExistingDomain(SPECIFIED, Money.of(USD, 3));
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_response.xml",
|
||||
false,
|
||||
ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew", "FEE", "9.0", "PERIOD", "3"),
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_renewCommandStandard_internalRegistration() throws Exception {
|
||||
createTld("tld");
|
||||
setEppInput(
|
||||
"domain_info_fee.xml",
|
||||
updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "renew", "PERIOD", "1"));
|
||||
persistTestEntities("example.tld", false);
|
||||
setUpBillingEventForExistingDomain(SPECIFIED, Money.of(USD, 3));
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_response.xml",
|
||||
false,
|
||||
ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew", "FEE", "3.0", "PERIOD", "1"),
|
||||
true);
|
||||
}
|
||||
|
||||
/** Test transfer command on a premium label. */
|
||||
|
@ -829,10 +952,12 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "transfer",
|
||||
"PERIOD", "1"));
|
||||
persistTestEntities("rich.example", false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_premium_response.xml",
|
||||
false,
|
||||
ImmutableMap.of("COMMAND", "transfer", "DESCRIPTION", "renew"));
|
||||
ImmutableMap.of("COMMAND", "transfer", "DESCRIPTION", "renew"),
|
||||
true);
|
||||
}
|
||||
|
||||
/** Test restore command on a premium label. */
|
||||
|
@ -847,7 +972,9 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "restore",
|
||||
"PERIOD", "1"));
|
||||
persistTestEntities("rich.example", false);
|
||||
doSuccessfulTest("domain_info_fee_restore_premium_response.xml", false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
doSuccessfulTest(
|
||||
"domain_info_fee_restore_premium_response.xml", false, ImmutableMap.of(), true);
|
||||
}
|
||||
|
||||
/** Test setting the currency explicitly to a wrong value. */
|
||||
|
@ -861,6 +988,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"CURRENCY", "EUR",
|
||||
"PERIOD", "1"));
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
@ -889,6 +1017,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"PERIOD", "2",
|
||||
"UNIT", "m"));
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
@ -898,6 +1027,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
void testFeeExtension_commandPhase() {
|
||||
setEppInput("domain_info_fee_command_phase.xml");
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
@ -907,6 +1037,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
void testFeeExtension_commandSubphase() {
|
||||
setEppInput("domain_info_fee_command_subphase.xml");
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
@ -921,6 +1052,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "restore",
|
||||
"PERIOD", "2"));
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
@ -935,6 +1067,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase
|
|||
"COMMAND", "transfer",
|
||||
"PERIOD", "2"));
|
||||
persistTestEntities(false);
|
||||
setUpBillingEventForExistingDomain();
|
||||
EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
|
|
@ -69,6 +69,8 @@ import google.registry.model.ImmutableObject;
|
|||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Flag;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.contact.ContactAuthInfo;
|
||||
import google.registry.model.contact.ContactHistory;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
|
@ -330,6 +332,35 @@ public class DatabaseHelper {
|
|||
return persistedDomain;
|
||||
}
|
||||
|
||||
/** Persists a {@link Recurring} and {@link HistoryEntry} for a domain that already exists. */
|
||||
public static DomainBase persistBillingRecurrenceForDomain(
|
||||
DomainBase domain, RenewalPriceBehavior renewalPriceBehavior, @Nullable Money renewalPrice) {
|
||||
DomainHistory historyEntry =
|
||||
persistResource(
|
||||
new DomainHistory.Builder()
|
||||
.setRegistrarId(domain.getCreationRegistrarId())
|
||||
.setType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.setModificationTime(domain.getCreationTime())
|
||||
.setDomain(domain)
|
||||
.build());
|
||||
Recurring recurring =
|
||||
persistResource(
|
||||
new BillingEvent.Recurring.Builder()
|
||||
.setParent(historyEntry)
|
||||
.setRenewalPrice(renewalPrice)
|
||||
.setRenewalPriceBehavior(renewalPriceBehavior)
|
||||
.setRegistrarId(domain.getCreationRegistrarId())
|
||||
.setEventTime(domain.getCreationTime())
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setId(2L)
|
||||
.setReason(Reason.RENEW)
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setTargetId(domain.getDomainName())
|
||||
.build());
|
||||
return persistResource(
|
||||
domain.asBuilder().setAutorenewBillingEvent(recurring.createVKey()).build());
|
||||
}
|
||||
|
||||
public static ReservedList persistReservedList(String listName, String... lines) {
|
||||
return persistReservedList(listName, true, lines);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<fee:command>create</fee:command>
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">100.00</fee:fee>
|
||||
<fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.002Z">100.00
|
||||
<fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.000Z">100.00
|
||||
</fee:fee>
|
||||
<fee:class>premium</fee:class>
|
||||
</fee:cd>
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="0">rich.example</domain:name>
|
||||
<domain:reason>In use</domain:reason>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
|
||||
<fee:cd xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
|
||||
<fee:name>rich.example</fee:name>
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:command>create</fee:command>
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">100.00</fee:fee>
|
||||
<fee:class>premium</fee:class>
|
||||
</fee:cd>
|
||||
<fee:cd xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
|
||||
<fee:name>rich.example</fee:name>
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:command>renew</fee:command>
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">%RENEWPRICE%</fee:fee>
|
||||
</fee:cd>
|
||||
<fee:cd xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
|
||||
<fee:name>rich.example</fee:name>
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:command>transfer</fee:command>
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<!-- TODO(mcilwain): This should be non-premium once transfer flow
|
||||
changes are made. -->
|
||||
<fee:fee description="renew">100.00</fee:fee>
|
||||
<fee:class>premium</fee:class>
|
||||
</fee:cd>
|
||||
<fee:cd xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
|
||||
<fee:name>rich.example</fee:name>
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:command>restore</fee:command>
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
Loading…
Add table
Add a link
Reference in a new issue