diff --git a/config/presubmits.py b/config/presubmits.py index 9e25464cc..8118c2ea5 100644 --- a/config/presubmits.py +++ b/config/presubmits.py @@ -98,8 +98,8 @@ PRESUBMITS = { "File did not include the license header.", # Files must end in a newline - PresubmitCheck(r".*\n$", ("java", "js", "soy", "sql", "py", "sh", "gradle", "ts"), - {"node_modules/"}, REQUIRED): + PresubmitCheck(r".*\n$", ("java", "js", "soy", "sql", "py", "sh", "gradle", "ts", "xml"), + {"node_modules/", ".idea"}, REQUIRED): "Source files must end in a newline.", # System.(out|err).println should only appear in tools/ or load-testing/ diff --git a/core/src/main/java/google/registry/model/eppcommon/EppXmlTransformer.java b/core/src/main/java/google/registry/model/eppcommon/EppXmlTransformer.java index 165046612..569ddf092 100644 --- a/core/src/main/java/google/registry/model/eppcommon/EppXmlTransformer.java +++ b/core/src/main/java/google/registry/model/eppcommon/EppXmlTransformer.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableSet; import google.registry.model.ImmutableObject; import google.registry.model.eppinput.EppInput; import google.registry.model.eppoutput.EppOutput; +import google.registry.util.NonFinalForTesting; import google.registry.util.RegistryEnvironment; import google.registry.xml.ValidationMode; import google.registry.xml.XmlException; @@ -60,20 +61,35 @@ public class EppXmlTransformer { // XML schemas that should not be used in production (yet) private static final ImmutableSet NON_PROD_SCHEMAS = ImmutableSet.of("fee-std-v1.xsd"); - private static final XmlTransformer INPUT_TRANSFORMER = + // XML schemas that should only be used in production (for backcompat) + private static final ImmutableSet ONLY_PROD_SCHEMAS = + ImmutableSet.of("fee06.xsd", "fee11.xsd", "fee12.xsd"); + + // TODO(gbrodman): make this final when we can actually remove the old fee extensions and aren't + // relying on switching by environment + @NonFinalForTesting + private static XmlTransformer INPUT_TRANSFORMER = new XmlTransformer(getSchemas(), EppInput.class); - private static final XmlTransformer OUTPUT_TRANSFORMER = + // TODO(gbrodman): make this final when we can actually remove the old fee extensions and aren't + // relying on switching by environment + @NonFinalForTesting + private static XmlTransformer OUTPUT_TRANSFORMER = new XmlTransformer(getSchemas(), EppOutput.class); @VisibleForTesting public static ImmutableList getSchemas() { - if (RegistryEnvironment.get().equals(RegistryEnvironment.PRODUCTION)) { - return ALL_SCHEMAS.stream() - .filter(s -> !NON_PROD_SCHEMAS.contains(s)) - .collect(toImmutableList()); - } - return ALL_SCHEMAS; + ImmutableSet schemasToSkip = + RegistryEnvironment.get().equals(RegistryEnvironment.PRODUCTION) + ? NON_PROD_SCHEMAS + : ONLY_PROD_SCHEMAS; + return ALL_SCHEMAS.stream().filter(s -> !schemasToSkip.contains(s)).collect(toImmutableList()); + } + + @VisibleForTesting + public static void reloadTransformers() { + INPUT_TRANSFORMER = new XmlTransformer(getSchemas(), EppInput.class); + OUTPUT_TRANSFORMER = new XmlTransformer(getSchemas(), EppOutput.class); } public static void validateOutput(String xml) throws XmlException { diff --git a/core/src/main/java/google/registry/model/eppcommon/ProtocolDefinition.java b/core/src/main/java/google/registry/model/eppcommon/ProtocolDefinition.java index 0aa15471d..9f55ea5d0 100644 --- a/core/src/main/java/google/registry/model/eppcommon/ProtocolDefinition.java +++ b/core/src/main/java/google/registry/model/eppcommon/ProtocolDefinition.java @@ -17,6 +17,7 @@ package google.registry.model.eppcommon; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.Maps.uniqueIndex; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import google.registry.model.domain.fee06.FeeCheckCommandExtensionV06; @@ -33,6 +34,7 @@ import google.registry.model.domain.rgp.RgpUpdateExtension; import google.registry.model.domain.secdns.SecDnsCreateExtension; import google.registry.model.eppinput.EppInput.CommandExtension; import google.registry.model.eppoutput.EppResponse.ResponseExtension; +import google.registry.util.NonFinalForTesting; import google.registry.util.RegistryEnvironment; import jakarta.xml.bind.annotation.XmlSchema; import java.util.EnumSet; @@ -62,15 +64,15 @@ public class ProtocolDefinition { FEE_0_6( FeeCheckCommandExtensionV06.class, FeeCheckResponseExtensionV06.class, - ServiceExtensionVisibility.ALL), + ServiceExtensionVisibility.ONLY_IN_PRODUCTION), FEE_0_11( FeeCheckCommandExtensionV11.class, FeeCheckResponseExtensionV11.class, - ServiceExtensionVisibility.ALL), + ServiceExtensionVisibility.ONLY_IN_PRODUCTION), FEE_0_12( FeeCheckCommandExtensionV12.class, FeeCheckResponseExtensionV12.class, - ServiceExtensionVisibility.ALL), + ServiceExtensionVisibility.ONLY_IN_PRODUCTION), FEE_1_00( FeeCheckCommandExtensionStdV1.class, FeeCheckResponseExtensionStdV1.class, @@ -109,7 +111,7 @@ public class ProtocolDefinition { return clazz.getPackage().getAnnotation(XmlSchema.class).namespace(); } - private boolean isVisible() { + public boolean isVisible() { return switch (visibility) { case ALL -> true; case ONLY_IN_PRODUCTION -> RegistryEnvironment.get().equals(RegistryEnvironment.PRODUCTION); @@ -134,14 +136,25 @@ public class ProtocolDefinition { } /** A set of all the visible extension URIs. */ - private static final ImmutableSet visibleServiceExtensionUris = - EnumSet.allOf(ServiceExtension.class).stream() - .filter(ServiceExtension::isVisible) - .map(ServiceExtension::getUri) - .collect(toImmutableSet()); + // TODO(gbrodman): make this final when we can actually remove the old fee extensions and aren't + // relying on switching by environment + @NonFinalForTesting private static ImmutableSet visibleServiceExtensionUris; + + static { + reloadServiceExtensionUris(); + } /** Return the set of all visible service extension URIs. */ public static ImmutableSet getVisibleServiceExtensionUris() { return visibleServiceExtensionUris; } + + @VisibleForTesting + public static void reloadServiceExtensionUris() { + visibleServiceExtensionUris = + EnumSet.allOf(ServiceExtension.class).stream() + .filter(ServiceExtension::isVisible) + .map(ServiceExtension::getUri) + .collect(toImmutableSet()); + } } diff --git a/core/src/test/java/google/registry/flows/FlowTestCase.java b/core/src/test/java/google/registry/flows/FlowTestCase.java index 4a26ff908..e27f5a622 100644 --- a/core/src/test/java/google/registry/flows/FlowTestCase.java +++ b/core/src/test/java/google/registry/flows/FlowTestCase.java @@ -135,28 +135,6 @@ public abstract class FlowTestCase { return TestDataHelper.loadFile(getClass(), filename, substitutions); } - /** - * Converts an input or response EPP message with draft fee extension v12 to std v1. - * - *

There is no practical changes between draft v12 and the v1 standard. This method allows us - * to reuse v12 test data. - */ - protected String loadFeeV12FileAsStdV1(String filename) { - String content = loadFile(filename); - return content.replace("urn:ietf:params:xml:ns:fee-0.12", "urn:ietf:params:xml:ns:epp:fee-1.0"); - } - - /** - * Converts an input or response EPP message with draft fee extension v12 to std v1. - * - *

There is no practical changes between draft v12 and the v1 standard. This method allows us - * to reuse v12 test data. - */ - protected String loadFeeV12FileAsStdV1(String filename, Map substitutions) { - String content = loadFile(filename, substitutions); - return content.replace("urn:ietf:params:xml:ns:fee-0.12", "urn:ietf:params:xml:ns:epp:fee-1.0"); - } - @Nullable protected String getClientTrid() throws Exception { return eppLoader.getEpp().getCommandWrapper().getClTrid().orElse(null); diff --git a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowOldFeeExtensionsTest.java b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowOldFeeExtensionsTest.java new file mode 100644 index 000000000..b904ab26a --- /dev/null +++ b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowOldFeeExtensionsTest.java @@ -0,0 +1,1321 @@ +// Copyright 2026 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.flows.domain; + +import static com.google.common.truth.Truth.assertThat; +import static google.registry.flows.domain.DomainCheckFlowTest.createReservedList; +import static google.registry.flows.domain.DomainCheckFlowTest.setUpDefaultToken; +import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.DEFAULT; +import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM; +import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED; +import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO; +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; +import static google.registry.model.tld.Tld.TldState.START_DATE_SUNRISE; +import static google.registry.testing.DatabaseHelper.assertNoBillingEvents; +import static google.registry.testing.DatabaseHelper.createTld; +import static google.registry.testing.DatabaseHelper.persistActiveDomain; +import static google.registry.testing.DatabaseHelper.persistBillingRecurrenceForDomain; +import static google.registry.testing.DatabaseHelper.persistPremiumList; +import static google.registry.testing.DatabaseHelper.persistReservedList; +import static google.registry.testing.DatabaseHelper.persistResource; +import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; +import static google.registry.util.DateTimeUtils.START_OF_TIME; +import static org.joda.money.CurrencyUnit.JPY; +import static org.joda.money.CurrencyUnit.USD; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.Ordering; +import google.registry.flows.EppException; +import google.registry.flows.FlowUtils.NotLoggedInException; +import google.registry.flows.domain.DomainCheckFlow.OnlyCheckedNamesCanBeFeeCheckedException; +import google.registry.flows.domain.DomainFlowUtils.BadPeriodUnitException; +import google.registry.flows.domain.DomainFlowUtils.CurrencyUnitMismatchException; +import google.registry.flows.domain.DomainFlowUtils.FeeChecksDontSupportPhasesException; +import google.registry.flows.domain.DomainFlowUtils.RestoresAreAlwaysForOneYearException; +import google.registry.flows.domain.DomainFlowUtils.TransfersAreAlwaysForOneYearException; +import google.registry.flows.domain.DomainFlowUtils.UnknownFeeCommandException; +import google.registry.model.billing.BillingBase.Flag; +import google.registry.model.billing.BillingBase.Reason; +import google.registry.model.billing.BillingRecurrence; +import google.registry.model.domain.Domain; +import google.registry.model.domain.DomainHistory; +import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName; +import google.registry.model.domain.token.AllocationToken; +import google.registry.model.domain.token.AllocationToken.TokenStatus; +import google.registry.model.eppcommon.StatusValue; +import google.registry.model.eppoutput.CheckData; +import google.registry.model.registrar.Registrar; +import google.registry.model.reporting.HistoryEntry; +import google.registry.model.tld.Tld; +import google.registry.model.tld.Tld.TldState; +import google.registry.testing.DatabaseHelper; +import java.math.BigDecimal; +import org.joda.money.Money; +import org.joda.time.DateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +/** Tests for {@link DomainCheckFlow} that use the older (0.6, 0.11, 0.12) fee extensions. */ +public class DomainCheckFlowOldFeeExtensionsTest + extends ProductionSimulatingFeeExtensionsTest { + + @BeforeEach + void oldFeeExtensionTestBeforeEach() { + createTld("tld", TldState.QUIET_PERIOD); + persistResource(Tld.get("tld").asBuilder().setReservedLists(createReservedList()).build()); + } + + @Test + void testNotLoggedIn_takesPrecedenceOverUndeclaredExtensions() { + // Attempt to use the fee extension, but there is no login session and no supported extensions. + setEppInput("domain_check_fee_v06.xml", ImmutableMap.of("CURRENCY", "USD")); + sessionMetadata.setRegistrarId(null); + sessionMetadata.setServiceExtensionUris(ImmutableSet.of()); + // NotLoggedIn should be thrown, not UndeclaredServiceExtensionException. + EppException thrown = assertThrows(NotLoggedInException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + /** Test the same as {@link #testFeeExtension_multipleCommands_v06} with premium labels. */ + @Test + void testFeeExtension_premiumLabels_v06() throws Exception { + createTld("example"); + setEppInput("domain_check_fee_premium_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v06.xml")); + } + + /** Test the same as {@link #testFeeExtension_multipleCommands_v06} with premium labels. */ + @Test + void testFeeExtension_premiumLabels_doesNotApplyDefaultToken_v06() throws Exception { + createTld("example"); + AllocationToken defaultToken = + persistResource( + new AllocationToken.Builder() + .setToken("bbbbb") + .setTokenType(DEFAULT_PROMO) + .setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar")) + .setAllowedTlds(ImmutableSet.of("example")) + .setDiscountPremiums(false) + .setDiscountFraction(0.5) + .build()); + persistResource( + Tld.get("example") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey())) + .build()); + setEppInput("domain_check_fee_premium_v06.xml"); + 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_withNonPremiumRenewalBehavior_renewPriceOnly() + throws Exception { + createTld("example"); + persistBillingRecurrenceForDomain(persistActiveDomain("rich.example"), NONPREMIUM, null); + setEppInput("domain_check_fee_premium_v06_renew_only.xml"); + runFlowAssertResponse( + loadFile( + "domain_check_fee_response_domain_exists_v06_renew_only.xml", + ImmutableMap.of("RENEWPRICE", "11.00"))); + } + + @Test + void testFeeExtension_existingPremiumDomain_withNonPremiumRenewalBehavior_transferPriceOnly() + throws Exception { + createTld("example"); + persistBillingRecurrenceForDomain(persistActiveDomain("rich.example"), NONPREMIUM, null); + setEppInput("domain_check_fee_premium_v06_transfer_only.xml"); + runFlowAssertResponse( + loadFile( + "domain_check_fee_response_domain_exists_v06_transfer_only.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"); + setEppInput("domain_check_fee_premium_v06.xml"); + clock.setTo(DateTime.parse("2010-01-01T10:00:00Z")); + persistResource( + Tld.get("example") + .asBuilder() + .setEapFeeSchedule( + new ImmutableSortedMap.Builder(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)) + .build()) + .build()); + + runFlowAssertResponse(loadFile("domain_check_fee_premium_eap_response_v06.xml")); + } + + @Test + void testFeeExtension_premium_eap_v06_withRenewalOnRestore() throws Exception { + createTld("example"); + 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( + Tld.get("example") + .asBuilder() + .setEapFeeSchedule( + new ImmutableSortedMap.Builder(Ordering.natural()) + .put(START_OF_TIME, 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")); + } + + @Test + void testFeeExtension_premiumLabels_v11_create() throws Exception { + createTld("example"); + setEppInput("domain_check_fee_premium_v11_create.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_create.xml")); + } + + @Test + void testFeeExtension_premiumLabels_doesNotApplyDefaultToken_v11() throws Exception { + createTld("example"); + AllocationToken defaultToken = + persistResource( + new AllocationToken.Builder() + .setToken("bbbbb") + .setTokenType(DEFAULT_PROMO) + .setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar")) + .setAllowedTlds(ImmutableSet.of("example")) + .setDiscountPremiums(false) + .setDiscountFraction(0.5) + .build()); + persistResource( + Tld.get("example") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey())) + .build()); + setEppInput("domain_check_fee_premium_v11_create.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_create.xml")); + } + + @Test + void testFeeExtension_premiumLabels_v11_renew() throws Exception { + createTld("example"); + setEppInput("domain_check_fee_premium_v11_renew.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_renew.xml")); + } + + @Test + void testFeeExtension_premiumLabels_v11_transfer() throws Exception { + createTld("example"); + setEppInput("domain_check_fee_premium_v11_transfer.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_transfer.xml")); + } + + @Test + void testFeeExtension_premiumLabels_v11_restore() throws Exception { + createTld("example"); + setEppInput("domain_check_fee_premium_v11_restore.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_restore.xml")); + } + + @Test + void testFeeExtension_premiumLabels_v11_restore_withRenewal() throws Exception { + setEppInput("domain_check_fee_premium_v11_restore.xml"); + createTld("example"); + persistPendingDeleteDomain("rich.example"); + runFlowAssertResponse( + loadFile("domain_check_fee_premium_response_v11_restore_with_renewal.xml")); + } + + @Test + void testFeeExtension_premiumLabels_v11_update() throws Exception { + createTld("example"); + setEppInput("domain_check_fee_premium_v11_update.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_update.xml")); + } + + @Test + void testFeeExtension_premiumLabels_v12() throws Exception { + createTld("example"); + setEppInput("domain_check_fee_premium_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v12.xml")); + } + + @Test + void testFeeExtension_multipleCommands_defaultTokenOnlyOnCreate_v12() throws Exception { + setUpDefaultToken(); + setEppInput("domain_check_fee_multiple_commands_v12.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_multiple_commands_default_token_response_v12.xml")); + } + + @Disabled("TODO(b/454680236): broken test") + @Test + void testFeeExtension_defaultToken_notValidForAllLabels_v06() throws Exception { + createTld("example"); + AllocationToken defaultToken = + persistResource( + new AllocationToken.Builder() + .setToken("bbbbb") + .setTokenType(DEFAULT_PROMO) + .setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar")) + .setAllowedTlds(ImmutableSet.of("example")) + .setDiscountPremiums(false) + .setDiscountFraction(0.5) + .build()); + persistResource( + Tld.get("example") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey())) + .build()); + setEppInput("domain_check_fee_default_token_multiple_names_v06.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_default_token_multiple_names_response_v06.xml")); + } + + @Disabled("TODO(b/454680236): broken") + @Test + void testFeeExtension_defaultToken_notValidForAllLabels_v11() throws Exception { + createTld("example"); + AllocationToken defaultToken = + persistResource( + new AllocationToken.Builder() + .setToken("bbbbb") + .setTokenType(DEFAULT_PROMO) + .setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar")) + .setAllowedTlds(ImmutableSet.of("example")) + .setDiscountPremiums(false) + .setDiscountFraction(0.5) + .build()); + persistResource( + Tld.get("example") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey())) + .build()); + setEppInput("domain_check_fee_default_token_multiple_names_v11.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_default_token_multiple_names_response_v11.xml")); + } + + @Disabled("TODO(b/454680236): broken test") + @Test + void testFeeExtension_defaultToken_notValidForAllLabels_v12() throws Exception { + createTld("example"); + AllocationToken defaultToken = + persistResource( + new AllocationToken.Builder() + .setToken("bbbbb") + .setTokenType(DEFAULT_PROMO) + .setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar")) + .setAllowedTlds(ImmutableSet.of("example")) + .setDiscountPremiums(false) + .setDiscountFraction(0.5) + .build()); + persistResource( + Tld.get("example") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey())) + .build()); + setEppInput("domain_check_fee_default_token_multiple_names_v12.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_default_token_multiple_names_response_v12.xml")); + } + + /** + * Test commands for create, renew, transfer, restore and update with implicit period and + * currency. + */ + @Test + void testFeeExtension_multipleCommands_v06() throws Exception { + setEppInput("domain_check_fee_multiple_commands_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_multiple_commands_response_v06.xml")); + } + + @Test + void testFeeExtension_multipleCommands_tokenNotValidForSome_v06() throws Exception { + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(UNLIMITED_USE) + .setAllowedEppActions(ImmutableSet.of(CommandName.CREATE, CommandName.TRANSFER)) + .setDiscountFraction(0.1) + .build()); + setEppInput("domain_check_fee_multiple_commands_allocationtoken_v06.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_multiple_commands_allocationtoken_response_v06.xml")); + } + + @Test + void testFeeExtension_multipleCommands_defaultTokenOnlyOnCreate_v06() throws Exception { + setUpDefaultToken(); + setEppInput("domain_check_fee_multiple_commands_v06.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_multiple_commands_default_token_response_v06.xml")); + } + + // Version 11 cannot have multiple commands. + + @Test + void testFeeExtension_multipleCommands_v12() throws Exception { + setEppInput("domain_check_fee_multiple_commands_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_multiple_commands_response_v12.xml")); + } + + @Test + void testFeeExtension_multipleCommands_tokenNotValidForSome_v12() throws Exception { + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(UNLIMITED_USE) + .setAllowedEppActions(ImmutableSet.of(CommandName.CREATE, CommandName.TRANSFER)) + .setDiscountFraction(0.1) + .build()); + setEppInput("domain_check_fee_multiple_commands_allocationtoken_v12.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_multiple_commands_allocationtoken_response_v12.xml")); + } + + @Test + void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v06() throws Exception { + createTld("tld", START_DATE_SUNRISE); + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_v06.xml")); + } + + @Test + void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v06_withRestoreRenewals() + throws Exception { + createTld("tld", START_DATE_SUNRISE); + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + persistPendingDeleteDomain("reserved.tld"); + persistPendingDeleteDomain("allowedinsunrise.tld"); + persistPendingDeleteDomain("collision.tld"); + persistPendingDeleteDomain("premiumcollision.tld"); + setEppInput("domain_check_fee_reserved_v06.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_reserved_sunrise_response_v06_with_renewals.xml")); + } + + @Test + void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_create() throws Exception { + createTld("tld", START_DATE_SUNRISE); + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v11_create.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_v11_create.xml")); + } + + @Test + void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_renew() throws Exception { + createTld("tld", START_DATE_SUNRISE); + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v11_renew.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_v11_renew.xml")); + } + + @Test + void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_transfer() throws Exception { + createTld("tld", START_DATE_SUNRISE); + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v11_transfer.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_v11_transfer.xml")); + } + + @Test + void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_restore() throws Exception { + createTld("tld", START_DATE_SUNRISE); + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v11_restore.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_v11_restore.xml")); + } + + @Test + void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v12() throws Exception { + createTld("tld", START_DATE_SUNRISE); + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_v12.xml")); + } + + @Test + void testFeeExtension_wrongCurrency_v06() { + setEppInput("domain_check_fee_euro_v06.xml"); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_wrongCurrency_v11() { + setEppInput("domain_check_fee_euro_v11.xml"); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_invalidCommand_v06() { + setEppInput("domain_check_fee_invalid_command_v06.xml"); + EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_invalidCommand_v11() { + setEppInput("domain_check_fee_invalid_command_v11.xml"); + EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_invalidCommand_v12() { + setEppInput("domain_check_fee_invalid_command_v12.xml"); + EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_reservedName_v06() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_v06.xml")); + } + + @Test + void testFeeExtension_reservedName_restoreFeeWithDupes_v06() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .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. + persistBillingRecurrenceForDomain(persistActiveDomain("allowedinsunrise.tld"), DEFAULT, null); + setEppInput("domain_check_fee_reserved_dupes_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_dupes_v06.xml")); + } + + /** The tests must be split up for version 11, which allows only one command at a time. */ + @Test + void testFeeExtension_reservedName_v11_create() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v11_create.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_v11_create.xml")); + } + + @Test + void testFeeExtension_reservedName_v11_renew() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v11_renew.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_v11_renew.xml")); + } + + @Test + void testFeeExtension_reservedName_v11_transfer() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v11_transfer.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_v11_transfer.xml")); + } + + @Test + void testFeeExtension_reservedName_v11_restore() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v11_restore.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_v11_restore.xml")); + } + + @Test + void testFeeExtension_reservedName_v11_restore_withRenewals() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + persistPendingDeleteDomain("reserved.tld"); + persistPendingDeleteDomain("allowedinsunrise.tld"); + persistPendingDeleteDomain("collision.tld"); + persistPendingDeleteDomain("premiumcollision.tld"); + setEppInput("domain_check_fee_reserved_v11_restore.xml"); + runFlowAssertResponse( + loadFile("domain_check_fee_reserved_response_v11_restore_with_renewals.xml")); + } + + @Test + void testFeeExtension_reservedName_v12() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70")) + .build()); + setEppInput("domain_check_fee_reserved_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_v12.xml")); + } + + @Test + void testFeeExtension_reservedName_restoreFeeWithDupes_v12() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists(createReservedList()) + .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. + setEppInput("domain_check_fee_reserved_dupes_v12.xml"); + persistBillingRecurrenceForDomain(persistActiveDomain("allowedinsunrise.tld"), DEFAULT, null); + runFlowAssertResponse(loadFile("domain_check_fee_reserved_dupes_response_v12.xml")); + } + + @Test + void testFeeExtension_periodNotInYears_v06() { + setEppInput("domain_check_fee_bad_period_v06.xml"); + EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_periodNotInYears_v11() { + setEppInput("domain_check_fee_bad_period_v11.xml"); + EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_unknownCommand_v06() { + setEppInput("domain_check_fee_unknown_command_v06.xml"); + EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_unknownCommand_v11() { + setEppInput("domain_check_fee_unknown_command_v11.xml"); + EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + /** Test multiyear periods and explicitly correct currency and that the avail extension is ok. */ + @Test + void testFeeExtension_v06() throws Exception { + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v06.xml", ImmutableMap.of("CURRENCY", "USD")); + runFlowAssertResponse(loadFile("domain_check_fee_response_v06.xml")); + } + + @Test + void testFeeExtension_defaultToken_v06() throws Exception { + setUpDefaultToken(); + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v06.xml", ImmutableMap.of("CURRENCY", "USD")); + runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_v06.xml")); + } + + @Test + void testFeeExtension_multipleReservations() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists( + persistReservedList("example-sunrise", "allowedinsunrise,ALLOWED_IN_SUNRISE")) + .build()); + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v06.xml", ImmutableMap.of("CURRENCY", "USD")); + runFlowAssertResponse(loadFile("domain_check_fee_response_v06.xml")); + } + + @Test + void testFeeExtension_v11() throws Exception { + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v11.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_response_v11.xml")); + } + + @Test + void testFeeExtension_defaultToken_v11() throws Exception { + setUpDefaultToken(); + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v11.xml", ImmutableMap.of("CURRENCY", "USD")); + runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_v11.xml")); + } + + @Test + void testFeeExtension_v12() throws Exception { + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_response_v12.xml")); + } + + @Test + void testFeeExtension_defaultToken_v12() throws Exception { + setUpDefaultToken(); + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v12.xml", ImmutableMap.of("CURRENCY", "USD")); + runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_v12.xml")); + } + + @Test + void testFeeExtension_premiumLabels_v12_specifiedPriceRenewal_renewPriceOnly() throws Exception { + createTld("example"); + persistBillingRecurrenceForDomain( + persistActiveDomain("rich.example"), SPECIFIED, Money.of(USD, new BigDecimal("27.74"))); + setEppInput("domain_check_fee_premium_v12_renew_only.xml"); + runFlowAssertResponse( + loadFile( + "domain_check_fee_premium_response_v12_renew_only.xml", + ImmutableMap.of("RENEWPRICE", "27.74"))); + } + + @Test + void testFeeExtension_premiumLabels_doesNotApplyDefaultToken_v12() throws Exception { + createTld("example"); + AllocationToken defaultToken = + persistResource( + new AllocationToken.Builder() + .setToken("bbbbb") + .setTokenType(DEFAULT_PROMO) + .setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar")) + .setAllowedTlds(ImmutableSet.of("example")) + .setDiscountPremiums(false) + .setDiscountFraction(0.5) + .build()); + persistResource( + Tld.get("example") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey())) + .build()); + setEppInput("domain_check_fee_premium_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v12.xml")); + } + + @Test + void testFeeExtension_commandSubphase_v06() { + setEppInput("domain_check_fee_command_subphase_v06.xml"); + EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_commandSubphase_v11() { + setEppInput("domain_check_fee_command_subphase_v11.xml"); + EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + // This test is only relevant for v06, since domain names are not specified after. + @Test + void testFeeExtension_feeCheckNotInAvailabilityCheck() { + setEppInput("domain_check_fee_not_in_avail.xml"); + EppException thrown = + assertThrows(OnlyCheckedNamesCanBeFeeCheckedException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_multiyearRestore_v06() { + setEppInput("domain_check_fee_multiyear_restore_v06.xml"); + EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_multiyearRestore_v11() { + setEppInput("domain_check_fee_multiyear_restore_v11.xml"); + EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_multiyearTransfer_v06() { + setEppInput("domain_check_fee_multiyear_transfer_v06.xml"); + EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_multiyearTransfer_v11() { + setEppInput("domain_check_fee_multiyear_transfer_v11.xml"); + EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_premiumLabels_v12_withRenewalOnRestore() throws Exception { + createTld("example"); + setEppInput("domain_check_fee_premium_v12.xml"); + persistPendingDeleteDomain("rich.example"); + runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v12_with_renewal.xml")); + } + + @Test + void testFeeExtension_commandWithPhase_v06() { + setEppInput("domain_check_fee_command_phase_v06.xml"); + EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_commandWithPhase_v11() { + setEppInput("domain_check_fee_command_phase_v11.xml"); + EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_multiyearRestore_v12() { + setEppInput("domain_check_fee_multiyear_restore_v12.xml"); + EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_multiyearTransfer_v12() { + setEppInput("domain_check_fee_multiyear_transfer_v12.xml"); + EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_unknownCommand_v12() { + setEppInput("domain_check_fee_unknown_command_v12.xml"); + EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_wrongCurrency_v12() { + setEppInput("domain_check_fee_euro_v12.xml"); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_periodNotInYears_v12() { + setEppInput("domain_check_fee_bad_period_v12.xml"); + EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_commandWithPhase_v12() { + setEppInput("domain_check_fee_command_phase_v12.xml"); + EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_commandSubphase_v12() { + setEppInput("domain_check_fee_command_subphase_v12.xml"); + EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_multipleCurencies_v12() throws Exception { + persistResource( + createTld("example") + .asBuilder() + .setCurrency(JPY) + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800))) + .setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800))) + .setRenewBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800))) + .setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800)) + .setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800)) + .setRestoreBillingCost(Money.ofMajor(JPY, 800)) + .build()); + persistResource( + Registrar.loadByRegistrarId("TheRegistrar") + .get() + .asBuilder() + .setBillingAccountMap(ImmutableMap.of(USD, "foo", JPY, "bar")) + .build()); + setEppInput("domain_check_fee_multiple_currencies_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_multiple_currencies_response_v12.xml")); + } + + @Test + void testTieredPricingPromoResponse_v12() throws Exception { + sessionMetadata.setRegistrarId("NewRegistrar"); + setUpDefaultToken("NewRegistrar"); + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_tiered_promotion_fee_response_v12.xml")); + } + + @Test + void testTieredPricingPromo_registrarNotIncluded_standardResponse_v12() throws Exception { + setUpDefaultToken("NewRegistrar"); + persistActiveDomain("example1.tld"); + setEppInput("domain_check_fee_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_response_v12.xml")); + } + + @Test + void testTieredPricingPromo_registrarIncluded_noTokenActive_v12() throws Exception { + sessionMetadata.setRegistrarId("NewRegistrar"); + persistActiveDomain("example1.tld"); + + persistResource( + setUpDefaultToken("NewRegistrar") + .asBuilder() + .setTokenStatusTransitions( + ImmutableSortedMap.of( + START_OF_TIME, + TokenStatus.NOT_STARTED, + clock.nowUtc().plusDays(1), + TokenStatus.VALID)) + .build()); + + setEppInput("domain_check_fee_v12.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_response_v12.xml")); + } + + @Test + void testFeeExtension_fractionalCost_v06() throws Exception { + // Note that the response xml expects to see "11.10" with two digits after the decimal point. + // This works because Money.getAmount(), used in the flow, returns a BigDecimal that is set to + // display the number of digits that is conventional for the given currency. + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 11.1))) + .build()); + setEppInput("domain_check_fee_fractional_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_fee_fractional_response_v06.xml")); + } + + @Test + void testSuccess_allocationTokenPromotion_doesNotUseValidDefaultToken_singleYear_v06() + throws Exception { + setUpDefaultToken(); + createTld("example"); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(UNLIMITED_USE) + .setDiscountFraction(0.5) + .setDiscountYears(2) + .setAllowedEppActions(ImmutableSet.of(CommandName.CREATE)) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().minusDays(1), TokenStatus.VALID) + .put(clock.nowUtc().plusDays(1), TokenStatus.ENDED) + .build()) + .build()); + setEppInput("domain_check_allocationtoken_fee_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_allocationtoken_fee_response_v06.xml")); + } + + @Test + void testSuccess_thirtyDomains_restoreFees_v06() throws Exception { + // Note that 30 is more than 25, which is the maximum # of entity groups you can enlist in a + // single database transaction (each Domain entity is in a separate entity group). + // It's also pretty common for registrars to send large domain checks. + setEppInput("domain_check_fee_thirty_domains_v06.xml"); + // example-00.tld won't exist and thus will not have a renew fee like the others. + for (int i = 1; i < 30; i++) { + persistPendingDeleteDomain(String.format("example-%02d.tld", i)); + } + runFlowAssertResponse(loadFile("domain_check_fee_response_thirty_domains_v06.xml")); + } + + @Test + void testSuccess_allocationTokenPromotion_multiYear_v06() throws Exception { + createTld("tld"); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(SINGLE_USE) + .setDomainName("single.tld") + .setDiscountFraction(0.444) + .setDiscountYears(2) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().minusDays(1), TokenStatus.VALID) + .put(clock.nowUtc().plusDays(1), TokenStatus.ENDED) + .build()) + .build()); + setEppInput( + "domain_check_allocationtoken_promotion_v06.xml", ImmutableMap.of("DOMAIN", "single.tld")); + // 1-yr: 13 * .556 + // 2-yr: (13 + 11) * .556 + // 5-yr: 2-yr-cost + 3 * 11 + runFlowAssertResponse( + loadFile( + "domain_check_allocationtoken_promotion_response_v06.xml", + new ImmutableMap.Builder() + .put("DOMAIN", "single.tld") + .put("COST_1YR", "7.23") + .put("COST_2YR", "13.34") + .put("COST_5YR", "46.34") + .put("FEE_CLASS", "") + .build())); + } + + @Test + void testSuccess_allocationTokenPromotion_multiYearAndPremiums() throws Exception { + createTld("example"); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(SINGLE_USE) + .setDomainName("rich.example") + .setDiscountFraction(0.9) + .setDiscountYears(3) + .setDiscountPremiums(true) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().minusDays(1), TokenStatus.VALID) + .put(clock.nowUtc().plusDays(1), TokenStatus.ENDED) + .build()) + .build()); + setEppInput( + "domain_check_allocationtoken_promotion_v06.xml", + ImmutableMap.of("DOMAIN", "rich.example")); + runFlowAssertResponse( + loadFile( + "domain_check_allocationtoken_promotion_response_v06.xml", + new ImmutableMap.Builder() + .put("DOMAIN", "rich.example") + .put("COST_1YR", "10.00") + .put("COST_2YR", "20.00") + .put("COST_5YR", "230.00") + .put("FEE_CLASS", "premium") + .build())); + } + + @Test + void testSuccess_allocationToken_premiumAnchorTenant_noFee_v06() throws Exception { + createTld("example"); + persistResource( + Tld.get("tld") + .asBuilder() + .setPremiumList(persistPremiumList("example1", USD, "example1,USD 100")) + .build()); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(SINGLE_USE) + .setRegistrationBehavior(AllocationToken.RegistrationBehavior.ANCHOR_TENANT) + .setDomainName("example1.tld") + .build()); + setEppInput("domain_check_allocationtoken_fee_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_allocationtoken_fee_anchor_response_v06.xml")); + } + + @Test + void testSuccess_promotionNotActive_v06() throws Exception { + createTld("example"); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(UNLIMITED_USE) + .setDiscountFraction(0.5) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().plusDays(1), TokenStatus.VALID) + .put(clock.nowUtc().plusDays(60), TokenStatus.ENDED) + .build()) + .build()); + setEppInput("domain_check_allocationtoken_fee_v06.xml"); + assertMutatingFlow(false); + assertThat(((CheckData) runFlow().getResponse().getResponseData().get(0)).getChecks()) + .containsExactly( + create(false, "example1.tld", "Alloc token not in promo period"), + create(false, "example2.example", "Alloc token not in promo period"), + create(false, "reserved.tld", "Alloc token not in promo period"), + create(false, "rich.example", "Alloc token not in promo period")); + assertNoBillingEvents(); // Checks are always free. + assertNoHistory(); // Checks don't create a history event. + } + + @Test + void testSuccess_allocationTokenPromotion_singleYear_v06() throws Exception { + createTld("example"); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(UNLIMITED_USE) + .setAllowedEppActions(ImmutableSet.of(CommandName.CREATE)) + .setDiscountFraction(0.5) + .setDiscountYears(2) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().minusDays(1), TokenStatus.VALID) + .put(clock.nowUtc().plusDays(1), TokenStatus.ENDED) + .build()) + .build()); + setEppInput("domain_check_allocationtoken_fee_v06.xml"); + runFlowAssertResponse(loadFile("domain_check_allocationtoken_fee_response_v06.xml")); + } + + @Test + void testSuccess_promoTokenNotValidForTld_v06() throws Exception { + createTld("example"); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(UNLIMITED_USE) + .setDiscountFraction(0.5) + .setAllowedTlds(ImmutableSet.of("example")) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().minusDays(1), TokenStatus.VALID) + .put(clock.nowUtc().plusDays(1), TokenStatus.ENDED) + .build()) + .build()); + setEppInput("domain_check_allocationtoken_fee_v06.xml"); + assertMutatingFlow(false); + assertThat(((CheckData) runFlow().getResponse().getResponseData().get(0)).getChecks()) + .containsExactly( + create(true, "example1.tld", null), + create(true, "example2.example", null), + create(false, "reserved.tld", "Reserved"), + create(true, "rich.example", null)); + assertNoBillingEvents(); // Checks are always free. + assertNoHistory(); // Checks don't create a history event. + } + + @Test + void testSuccess_promoTokenNotValidForRegistrar_v06() throws Exception { + createTld("example"); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(UNLIMITED_USE) + .setDiscountFraction(0.5) + .setAllowedRegistrarIds(ImmutableSet.of("someOtherClient")) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().minusDays(1), TokenStatus.VALID) + .put(clock.nowUtc().plusDays(1), TokenStatus.ENDED) + .build()) + .build()); + setEppInput("domain_check_allocationtoken_fee_v06.xml"); + assertMutatingFlow(false); + assertThat(((CheckData) runFlow().getResponse().getResponseData().get(0)).getChecks()) + .containsExactly( + create(false, "example1.tld", "Alloc token invalid for client"), + create(false, "example2.example", "Alloc token invalid for client"), + create(false, "reserved.tld", "Alloc token invalid for client"), + create(false, "rich.example", "Alloc token invalid for client")); + assertNoBillingEvents(); // Checks are always free. + assertNoHistory(); // Checks don't create a history event. + } + + @Test + void testSuccess_allocationTokenForReservedDomain_showsFee_v06() throws Exception { + setEppInput("domain_check_allocationtoken_fee_specificuse_v06.xml"); + createTld("example"); + persistResource( + new AllocationToken.Builder() + .setDomainName("specificuse.tld") + .setToken("abc123") + .setTokenType(SINGLE_USE) + .build()); + // Fees are shown for all non-reserved domains and the reserved domain matching this + // allocation token. + runFlowAssertResponse( + loadFile("domain_check_allocationtoken_fee_specificuse_response_v06.xml")); + } + + @Test + void testSuccess_eapFeeCheck_date_v12() throws Exception { + runEapFeeCheckTestWithXmlInputOutput( + loadFile("domain_check_fee_date_v12.xml", ImmutableMap.of("CURRENCY", "USD")), + loadFile("domain_check_eap_fee_response_date_v12.xml")); + } + + @Test + void testSuccess_eapFeeCheck_v06() throws Exception { + runEapFeeCheckTestWithXmlInputOutput( + loadFile("domain_check_fee_v06.xml", ImmutableMap.of("CURRENCY", "USD")), + loadFile("domain_check_eap_fee_response_v06.xml")); + } + + @Test + void testSuccess_eapFeeCheck_v11() throws Exception { + runEapFeeCheckTestWithXmlInputOutput( + loadFile("domain_check_fee_v11.xml", ImmutableMap.of("CURRENCY", "USD")), + loadFile("domain_check_eap_fee_response_v11.xml")); + } + + @Test + void testSuccess_eapFeeCheck_v12() throws Exception { + runEapFeeCheckTestWithXmlInputOutput( + loadFile("domain_check_fee_v12.xml", ImmutableMap.of("CURRENCY", "USD")), + loadFile("domain_check_eap_fee_response_v12.xml")); + } + + private Domain persistPendingDeleteDomain(String domainName) { + Domain existingDomain = + persistResource( + DatabaseHelper.newDomain(domainName) + .asBuilder() + .setDeletionTime(clock.nowUtc().plusDays(25)) + .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()); + BillingRecurrence renewEvent = + persistResource( + new BillingRecurrence.Builder() + .setReason(Reason.RENEW) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId(existingDomain.getDomainName()) + .setRegistrarId("TheRegistrar") + .setEventTime(existingDomain.getCreationTime()) + .setRecurrenceEndTime(clock.nowUtc()) + .setDomainHistory(historyEntry) + .build()); + return persistResource( + existingDomain.asBuilder().setAutorenewBillingEvent(renewEvent.createVKey()).build()); + } + + private void runEapFeeCheckTestWithXmlInputOutput(String inputXml, String outputXml) + throws Exception { + clock.setTo(DateTime.parse("2010-01-01T10:00:00Z")); + persistActiveDomain("example1.tld"); + persistResource( + Tld.get("tld") + .asBuilder() + .setEapFeeSchedule( + new ImmutableSortedMap.Builder(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)) + .build()) + .build()); + setEppInputXml(inputXml); + runFlowAssertResponse(outputXml); + } +} diff --git a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java index 5ef629653..19521efd2 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java @@ -16,7 +16,6 @@ package google.registry.flows.domain; import static google.registry.bsa.persistence.BsaTestingUtils.persistBsaLabel; import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.DEFAULT; -import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM; import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED; import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO; import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA; @@ -46,10 +45,10 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.Ordering; import google.registry.flows.EppException; +import google.registry.flows.FlowUtils.GenericXmlSyntaxErrorException; import google.registry.flows.FlowUtils.NotLoggedInException; import google.registry.flows.FlowUtils.UnknownCurrencyEppException; import google.registry.flows.ResourceCheckFlowTestCase; -import google.registry.flows.domain.DomainCheckFlow.OnlyCheckedNamesCanBeFeeCheckedException; import google.registry.flows.domain.DomainFlowUtils.BadCommandForRegistryPhaseException; import google.registry.flows.domain.DomainFlowUtils.BadDomainNameCharacterException; import google.registry.flows.domain.DomainFlowUtils.BadDomainNamePartsCountException; @@ -89,17 +88,11 @@ import google.registry.model.tld.Tld.TldState; import google.registry.model.tld.label.ReservedList; import google.registry.testing.DatabaseHelper; import java.math.BigDecimal; -import java.util.Map; import java.util.Optional; -import java.util.stream.Stream; import org.joda.money.Money; import org.joda.time.DateTime; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; /** Unit tests for {@link DomainCheckFlow}. */ class DomainCheckFlowTest extends ResourceCheckFlowTestCase { @@ -109,7 +102,7 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase() .put("DOMAIN", "rich.example") .put("COST_1YR", "10.00") @@ -516,7 +500,7 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase() .put("DOMAIN", "single.tld") .put("COST_1YR", "7.23") @@ -550,7 +535,7 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase(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)) - .build()) - .build()); - - runFlowAssertResponse(loadFile("domain_check_fee_premium_eap_response_v06.xml")); - } - - @Test - void testFeeExtension_premium_eap_v06_withRenewalOnRestore() throws Exception { - createTld("example"); - 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( - Tld.get("example") - .asBuilder() - .setEapFeeSchedule( - new ImmutableSortedMap.Builder(Ordering.natural()) - .put(START_OF_TIME, 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")); - } - - @Test - void testFeeExtension_premiumLabels_v11_create() throws Exception { - createTld("example"); - setEppInput("domain_check_fee_premium_v11_create.xml"); - runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_create.xml")); - } - - @Test - void testFeeExtension_premiumLabels_doesNotApplyDefaultToken_v11() throws Exception { - createTld("example"); - AllocationToken defaultToken = - persistResource( - new AllocationToken.Builder() - .setToken("bbbbb") - .setTokenType(DEFAULT_PROMO) - .setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar")) - .setAllowedTlds(ImmutableSet.of("example")) - .setDiscountPremiums(false) - .setDiscountFraction(0.5) - .build()); - persistResource( - Tld.get("example") - .asBuilder() - .setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey())) - .build()); - setEppInput("domain_check_fee_premium_v11_create.xml"); - runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_create.xml")); - } - - @Test - void testFeeExtension_premiumLabels_v11_renew() throws Exception { - createTld("example"); - setEppInput("domain_check_fee_premium_v11_renew.xml"); - runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_renew.xml")); - } - - @Test - void testFeeExtension_premiumLabels_v11_transfer() throws Exception { - createTld("example"); - setEppInput("domain_check_fee_premium_v11_transfer.xml"); - runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_transfer.xml")); - } - - @Test - void testFeeExtension_premiumLabels_v11_restore() throws Exception { - createTld("example"); - setEppInput("domain_check_fee_premium_v11_restore.xml"); - runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_restore.xml")); - } - - @Test - void testFeeExtension_premiumLabels_v11_restore_withRenewal() throws Exception { - setEppInput("domain_check_fee_premium_v11_restore.xml"); - createTld("example"); - persistPendingDeleteDomain("rich.example"); - runFlowAssertResponse( - loadFile("domain_check_fee_premium_response_v11_restore_with_renewal.xml")); - } - - @Test - void testFeeExtension_premiumLabels_v11_update() throws Exception { - createTld("example"); - setEppInput("domain_check_fee_premium_v11_update.xml"); - runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_update.xml")); - } - - @Test - void testFeeExtension_premiumLabels_v12() throws Exception { - createTld("example"); - setEppInput("domain_check_fee_premium_v12.xml"); - runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v12.xml")); - } - @Test void testFeeExtension_premiumLabels_std_v1() throws Exception { createTld("example"); @@ -1390,18 +970,6 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase substitutions) { - return isFeeStdV1 - ? test.loadFeeV12FileAsStdV1(filename, substitutions) - : test.loadFile(filename, substitutions); - } - } - - /** - * Fee versions 0.12 and 1.0 are the same in how they're requested (though not in the responses. - * As a result, for tests that throw an exception, we can use the same XML content. - */ - @SuppressWarnings("unused") - private static Stream provideFeeTestParams() { - return Stream.of( - Arguments.of("fee_std_v1", new FeeFileLoader(true)), - Arguments.of("fee_12", new FeeFileLoader(false))); - } } diff --git a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowOldFeeExtensionsTest.java b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowOldFeeExtensionsTest.java new file mode 100644 index 000000000..4c91ea6ca --- /dev/null +++ b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowOldFeeExtensionsTest.java @@ -0,0 +1,1153 @@ +// Copyright 2026 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.flows.domain; + +import static com.google.common.truth.Truth.assertThat; +import static google.registry.flows.FlowTestCase.UserPrivileges.SUPERUSER; +import static google.registry.model.billing.BillingBase.Flag.ANCHOR_TENANT; +import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM; +import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED; +import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS; +import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO; +import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE; +import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.testing.DatabaseHelper.assertBillingEvents; +import static google.registry.testing.DatabaseHelper.assertDomainDnsRequests; +import static google.registry.testing.DatabaseHelper.assertPollMessagesForResource; +import static google.registry.testing.DatabaseHelper.createTld; +import static google.registry.testing.DatabaseHelper.getHistoryEntries; +import static google.registry.testing.DatabaseHelper.loadAllOf; +import static google.registry.testing.DatabaseHelper.loadRegistrar; +import static google.registry.testing.DatabaseHelper.persistActiveContact; +import static google.registry.testing.DatabaseHelper.persistActiveDomain; +import static google.registry.testing.DatabaseHelper.persistActiveHost; +import static google.registry.testing.DatabaseHelper.persistReservedList; +import static google.registry.testing.DatabaseHelper.persistResource; +import static google.registry.testing.DomainSubject.assertAboutDomains; +import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; +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.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.Iterables; +import google.registry.flows.EppException; +import google.registry.flows.ExtensionManager.UndeclaredServiceExtensionException; +import google.registry.flows.FlowUtils.UnknownCurrencyEppException; +import google.registry.flows.domain.DomainFlowUtils.CurrencyUnitMismatchException; +import google.registry.flows.domain.DomainFlowUtils.CurrencyValueScaleException; +import google.registry.flows.domain.DomainFlowUtils.FeeDescriptionMultipleMatchesException; +import google.registry.flows.domain.DomainFlowUtils.FeeDescriptionParseException; +import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException; +import google.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException; +import google.registry.flows.domain.DomainFlowUtils.UnsupportedFeeAttributeException; +import google.registry.model.billing.BillingBase; +import google.registry.model.billing.BillingBase.Flag; +import google.registry.model.billing.BillingBase.Reason; +import google.registry.model.billing.BillingBase.RenewalPriceBehavior; +import google.registry.model.billing.BillingEvent; +import google.registry.model.billing.BillingRecurrence; +import google.registry.model.domain.Domain; +import google.registry.model.domain.DomainHistory; +import google.registry.model.domain.GracePeriod; +import google.registry.model.domain.rgp.GracePeriodStatus; +import google.registry.model.domain.token.AllocationToken; +import google.registry.model.domain.token.AllocationToken.RegistrationBehavior; +import google.registry.model.domain.token.AllocationToken.TokenStatus; +import google.registry.model.poll.PollMessage; +import google.registry.model.reporting.HistoryEntry; +import google.registry.model.tld.Tld; +import google.registry.persistence.VKey; +import google.registry.testing.DatabaseHelper; +import google.registry.tmch.LordnTaskUtils.LordnPhase; +import java.math.BigDecimal; +import java.util.Map; +import java.util.Optional; +import javax.annotation.Nullable; +import org.joda.money.Money; +import org.joda.time.DateTime; +import org.joda.time.Duration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Tests for {@link DomainCreateFlow} that use the old fee extensions (0.6, 0.11, 0.12). */ +public class DomainCreateFlowOldFeeExtensionsTest + extends ProductionSimulatingFeeExtensionsTest { + + private static final ImmutableMap FEE_06_MAP = + ImmutableMap.of("FEE_VERSION", "fee-0.6", "FEE_NS", "fee", "CURRENCY", "USD", "FEE", "15.00"); + private static final ImmutableMap FEE_11_MAP = + ImmutableMap.of( + "FEE_VERSION", "fee-0.11", "FEE_NS", "fee", "CURRENCY", "USD", "FEE", "15.00"); + private static final ImmutableMap FEE_12_MAP = + ImmutableMap.of( + "FEE_VERSION", "fee-0.12", "FEE_NS", "fee", "CURRENCY", "USD", "FEE", "15.00"); + + private static final String CLAIMS_KEY = "2013041500/2/6/9/rJ1NrDO92vDsAzf7EQzgjX4R0000000001"; + + private AllocationToken allocationToken; + + @BeforeEach + void beforeEachDomainCreateFlowOldFeeExtensionsTest() { + setEppInput("domain_create.xml", ImmutableMap.of("DOMAIN", "example.tld")); + clock.setTo(DateTime.parse("1999-04-03T22:00:00.0Z").minus(Duration.millis(2))); + createTld("tld"); + allocationToken = + persistResource( + new AllocationToken.Builder() + .setToken("abcDEF23456") + .setTokenType(SINGLE_USE) + .setDomainName("anchor.tld") + .build()); + persistResource( + Tld.get("tld") + .asBuilder() + .setReservedLists( + persistReservedList( + "tld-reserved", + "reserved,FULLY_BLOCKED", + "resdom,RESERVED_FOR_SPECIFIC_USE", + "anchor,RESERVED_FOR_ANCHOR_TENANT", + "test-and-validate,NAME_COLLISION", + "badcrash,NAME_COLLISION"), + persistReservedList("global-list", "resdom,FULLY_BLOCKED")) + .build()); + persistClaimsList(ImmutableMap.of("example-one", CLAIMS_KEY, "test-validate", CLAIMS_KEY)); + } + + private void persistContactsAndHosts() { + persistContactsAndHosts("net"); // domain_create.xml uses hosts on "net". + } + + /** + * Create host and contact entries for testing. + * + * @param hostTld the TLD of the host (which might be an external TLD) + */ + private void persistContactsAndHosts(String hostTld) { + for (int i = 1; i <= 14; ++i) { + persistActiveHost(String.format("ns%d.example.%s", i, hostTld)); + } + persistActiveContact("jd1234"); + persistActiveContact("sh8013"); + clock.advanceOneMilli(); + } + + private AllocationToken setupDefaultTokenWithDiscount() { + return setupDefaultTokenWithDiscount("TheRegistrar"); + } + + private AllocationToken setupDefaultTokenWithDiscount(String registrarId) { + return setupDefaultToken("bbbbb", 0.5, registrarId); + } + + private AllocationToken setupDefaultToken( + String token, double discountFraction, String registrarId) { + AllocationToken allocationToken = + persistResource( + new AllocationToken.Builder() + .setToken(token) + .setTokenType(DEFAULT_PROMO) + .setAllowedRegistrarIds(ImmutableSet.of(registrarId)) + .setAllowedTlds(ImmutableSet.of("tld")) + .setDiscountFraction(discountFraction) + .build()); + Tld tld = Tld.get("tld"); + persistResource( + tld.asBuilder() + .setDefaultPromoTokens( + ImmutableList.>builder() + .addAll(tld.getDefaultPromoTokens()) + .add(allocationToken.createVKey()) + .build()) + .build()); + return allocationToken; + } + + private void setEapForTld(String tld) { + persistResource( + Tld.get(tld) + .asBuilder() + .setEapFeeSchedule( + ImmutableSortedMap.of( + START_OF_TIME, + Money.of(USD, 0), + clock.nowUtc().minusDays(1), + Money.of(USD, 100), + clock.nowUtc().plusDays(1), + Money.of(USD, 0))) + .build()); + } + + private void doSuccessfulTest( + String domainTld, + String responseXmlFile, + UserPrivileges userPrivileges, + Map substitutions) + throws Exception { + assertMutatingFlow(true); + runFlowAssertResponse( + CommitMode.LIVE, userPrivileges, loadFile(responseXmlFile, substitutions)); + assertSuccessfulCreate(domainTld, ImmutableSet.of(), 24); + assertNoLordn(); + } + + private void doSuccessfulTest( + String domainTld, String responseXmlFile, Map substitutions) + throws Exception { + doSuccessfulTest(domainTld, responseXmlFile, UserPrivileges.NORMAL, substitutions); + } + + private void doSuccessfulTest(String domainTld) throws Exception { + doSuccessfulTest( + domainTld, "domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.tld")); + } + + private void doSuccessfulTest() throws Exception { + doSuccessfulTest("tld"); + } + + private void assertSuccessfulCreate(String domainTld, ImmutableSet expectedBillingFlags) + throws Exception { + assertSuccessfulCreate(domainTld, expectedBillingFlags, null, 24, null); + } + + private void assertSuccessfulCreate( + String domainTld, ImmutableSet expectedBillingFlags, double createCost) + throws Exception { + assertSuccessfulCreate(domainTld, expectedBillingFlags, null, createCost, null); + } + + private void assertSuccessfulCreate( + String domainTld, ImmutableSet expectedBillingFlags, AllocationToken token) + throws Exception { + assertSuccessfulCreate(domainTld, expectedBillingFlags, token, 24, null); + } + + private void assertSuccessfulCreate( + String domainTld, + ImmutableSet expectedBillingFlags, + AllocationToken token, + double createCost) + throws Exception { + assertSuccessfulCreate(domainTld, expectedBillingFlags, token, createCost, null); + } + + private void assertSuccessfulCreate( + String domainTld, + ImmutableSet expectedBillingFlags, + @Nullable AllocationToken token, + double createCost, + @Nullable Integer specifiedRenewCost) + throws Exception { + Domain domain = reloadResourceByForeignKey(); + + boolean isAnchorTenant = expectedBillingFlags.contains(ANCHOR_TENANT); + // Set up the creation cost. + Money eapFee = + Money.of( + Tld.get(domainTld).getCurrency(), + Tld.get(domainTld).getEapFeeFor(clock.nowUtc()).getCost()); + DateTime billingTime = + isAnchorTenant + ? clock.nowUtc().plus(Tld.get(domainTld).getAnchorTenantAddGracePeriodLength()) + : clock.nowUtc().plus(Tld.get(domainTld).getAddGracePeriodLength()); + assertLastHistoryContainsResource(domain); + DomainHistory historyEntry = getHistoryEntries(domain, DomainHistory.class).get(0); + assertAboutDomains() + .that(domain) + .hasRegistrationExpirationTime( + tm().transact(() -> tm().loadByKey(domain.getAutorenewBillingEvent()).getEventTime())) + .and() + .hasOnlyOneHistoryEntryWhich() + .hasType(HistoryEntry.Type.DOMAIN_CREATE) + .and() + .hasPeriodYears(2); + RenewalPriceBehavior expectedRenewalPriceBehavior = + isAnchorTenant + ? RenewalPriceBehavior.NONPREMIUM + : Optional.ofNullable(token) + .map(AllocationToken::getRenewalPriceBehavior) + .orElse(RenewalPriceBehavior.DEFAULT); + // There should be one bill for the create and one for the recurrence autorenew event. + BillingEvent createBillingEvent = + new BillingEvent.Builder() + .setReason(Reason.CREATE) + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId("TheRegistrar") + .setCost(Money.of(USD, BigDecimal.valueOf(createCost))) + .setPeriodYears(2) + .setEventTime(clock.nowUtc()) + .setBillingTime(billingTime) + .setFlags(expectedBillingFlags) + .setDomainHistory(historyEntry) + .setAllocationToken(Optional.ofNullable(token).map(t -> t.createVKey()).orElse(null)) + .build(); + + BillingRecurrence renewBillingEvent = + new BillingRecurrence.Builder() + .setReason(Reason.RENEW) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId("TheRegistrar") + .setEventTime(domain.getRegistrationExpirationTime()) + .setRecurrenceEndTime(END_OF_TIME) + .setDomainHistory(historyEntry) + .setRenewalPriceBehavior(expectedRenewalPriceBehavior) + .setRenewalPrice( + Optional.ofNullable(specifiedRenewCost) + .map(r -> Money.of(USD, BigDecimal.valueOf(r))) + .orElse(null)) + .build(); + + ImmutableSet.Builder expectedBillingEvents = + new ImmutableSet.Builder().add(createBillingEvent).add(renewBillingEvent); + + // If EAP is applied, a billing event for EAP should be present. + // EAP fees are bypassed for anchor tenant domains. + if (!isAnchorTenant && !eapFee.isZero()) { + BillingEvent eapBillingEvent = + new BillingEvent.Builder() + .setReason(Reason.FEE_EARLY_ACCESS) + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId("TheRegistrar") + .setPeriodYears(1) + .setCost(eapFee) + .setEventTime(clock.nowUtc()) + .setBillingTime(billingTime) + .setFlags(expectedBillingFlags) + .setDomainHistory(historyEntry) + .build(); + expectedBillingEvents.add(eapBillingEvent); + } + assertBillingEvents(expectedBillingEvents.build()); + assertPollMessagesForResource( + domain, + new PollMessage.Autorenew.Builder() + .setTargetId(domain.getDomainName()) + .setRegistrarId("TheRegistrar") + .setEventTime(domain.getRegistrationExpirationTime()) + .setMsg("Domain was auto-renewed.") + .setHistoryEntry(historyEntry) + .build()); + + assertGracePeriods( + domain.getGracePeriods(), + ImmutableMap.of( + GracePeriod.create( + GracePeriodStatus.ADD, domain.getRepoId(), billingTime, "TheRegistrar", null), + createBillingEvent)); + assertDomainDnsRequests(getUniqueIdFromCommand()); + } + + private void assertNoLordn() throws Exception { + assertAboutDomains() + .that(reloadResourceByForeignKey()) + .hasSmdId(null) + .and() + .hasLaunchNotice(null) + .and() + .hasLordnPhase(LordnPhase.NONE); + } + + @Test + void testFailure_wrongFeeAmount_v06() { + setEppInput("domain_create_fee.xml", FEE_06_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + persistContactsAndHosts(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmount_v11() { + setEppInput("domain_create_fee.xml", FEE_11_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + persistContactsAndHosts(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmount_v12() { + setEppInput("domain_create_fee.xml", FEE_12_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + persistContactsAndHosts(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_wrongFeeAmountTooHigh_defaultToken_v06() throws Exception { + setupDefaultTokenWithDiscount(); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 8))) + .build()); + // Expects fee of $24 + setEppInput("domain_create_fee.xml", FEE_06_MAP); + persistContactsAndHosts(); + // $15 is 50% off the first year registration ($8) and 0% 0ff the 2nd year (renewal at $11) + runFlowAssertResponse(loadFile("domain_create_response_fee.xml", FEE_06_MAP)); + } + + @Test + void testSuccess_wrongFeeAmountTooHigh_defaultToken_v11() throws Exception { + setupDefaultTokenWithDiscount(); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 8))) + .build()); + // Expects fee of $24 + setEppInput("domain_create_fee.xml", FEE_11_MAP); + persistContactsAndHosts(); + // $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year + runFlowAssertResponse(loadFile("domain_create_response_fee.xml", FEE_11_MAP)); + } + + @Test + void testSuccess_wrongFeeAmountTooHigh_defaultToken_v12() throws Exception { + setupDefaultTokenWithDiscount(); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 8))) + .build()); + // Expects fee of $24 + setEppInput("domain_create_fee.xml", FEE_12_MAP); + persistContactsAndHosts(); + // $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year + runFlowAssertResponse(loadFile("domain_create_response_fee.xml", FEE_12_MAP)); + } + + @Test + void testFailure_omitFeeExtensionOnLogin_v06() { + for (String uri : FEE_EXTENSION_URIS) { + removeServiceExtensionUri(uri); + } + createTld("net"); + setEppInput("domain_create_fee.xml", FEE_06_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UndeclaredServiceExtensionException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_omitFeeExtensionOnLogin_v11() { + for (String uri : FEE_EXTENSION_URIS) { + removeServiceExtensionUri(uri); + } + createTld("net"); + setEppInput("domain_create_fee.xml", FEE_11_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UndeclaredServiceExtensionException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_omitFeeExtensionOnLogin_v12() { + for (String uri : FEE_EXTENSION_URIS) { + removeServiceExtensionUri(uri); + } + createTld("net"); + setEppInput("domain_create_fee.xml", FEE_12_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UndeclaredServiceExtensionException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_eapFeeApplied_v06() throws Exception { + setEppInput( + "domain_create_eap_fee.xml", + new ImmutableMap.Builder() + .putAll(FEE_06_MAP) + .put("DESCRIPTION_1", "create") + .put("DESCRIPTION_2", "Early Access Period") + .build()); + persistContactsAndHosts(); + setEapForTld("tld"); + doSuccessfulTest("tld", "domain_create_response_eap_fee.xml", FEE_06_MAP); + } + + @Test + void testSuccess_eapFeeApplied_v11() throws Exception { + setEppInput( + "domain_create_eap_fee.xml", + new ImmutableMap.Builder() + .putAll(FEE_11_MAP) + .put("DESCRIPTION_1", "create") + .put("DESCRIPTION_2", "Early Access Period") + .build()); + persistContactsAndHosts(); + setEapForTld("tld"); + doSuccessfulTest("tld", "domain_create_response_eap_fee.xml", FEE_11_MAP); + } + + @Test + void testSuccess_eapFeeApplied_v12() throws Exception { + setEppInput( + "domain_create_eap_fee.xml", + new ImmutableMap.Builder() + .putAll(FEE_12_MAP) + .put("DESCRIPTION_1", "create") + .put("DESCRIPTION_2", "Early Access Period") + .build()); + persistContactsAndHosts(); + setEapForTld("tld"); + doSuccessfulTest("tld", "domain_create_response_eap_fee.xml", FEE_12_MAP); + } + + @Test + void testFailure_feeGivenInWrongScale_v06() { + setEppInput("domain_create_fee_bad_scale.xml", FEE_06_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v11() { + setEppInput("domain_create_fee_bad_scale.xml", FEE_11_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v12() { + setEppInput("domain_create_fee_bad_scale.xml", FEE_12_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v06() { + setEppInput("domain_create_fee_applied.xml", FEE_06_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v11() { + setEppInput("domain_create_fee_applied.xml", FEE_11_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v12() { + setEppInput("domain_create_fee_applied.xml", FEE_12_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmountTooLow_defaultToken_v06() throws Exception { + setupDefaultTokenWithDiscount(); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 100))) + .build()); + // Expects fee of $24 + setEppInput("domain_create_fee.xml", FEE_06_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmountTooLow_defaultToken_v11() throws Exception { + setupDefaultTokenWithDiscount(); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 100))) + .build()); + // Expects fee of $24 + setEppInput("domain_create_fee.xml", FEE_11_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmountTooLow_defaultToken_v12() throws Exception { + setupDefaultTokenWithDiscount(); + persistResource( + Tld.get("tld") + .asBuilder() + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 100))) + .build()); + // Expects fee of $24 + setEppInput("domain_create_fee.xml", FEE_12_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongCurrency_v06() { + setEppInput( + "domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "fee-0.6", "CURRENCY", "EUR")); + persistContactsAndHosts(); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongCurrency_v11() { + setEppInput( + "domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "fee-0.11", "CURRENCY", "EUR")); + persistContactsAndHosts(); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongCurrency_v12() { + setEppInput( + "domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "fee-0.12", "CURRENCY", "EUR")); + persistContactsAndHosts(); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v06() { + setEppInput("domain_create_fee_grace_period.xml", FEE_06_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v11() { + setEppInput("domain_create_fee_grace_period.xml", FEE_11_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v12() { + setEppInput("domain_create_fee_grace_period.xml", FEE_12_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v06() throws Exception { + setEppInput("domain_create_fee_defaults.xml", FEE_06_MAP); + persistContactsAndHosts(); + doSuccessfulTest( + "tld", + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.6", "FEE", "24.00")); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v11() throws Exception { + setEppInput("domain_create_fee_defaults.xml", FEE_11_MAP); + persistContactsAndHosts(); + doSuccessfulTest( + "tld", + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.11", "FEE", "24.00")); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v12() throws Exception { + setEppInput("domain_create_fee_defaults.xml", FEE_12_MAP); + persistContactsAndHosts(); + doSuccessfulTest( + "tld", + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.12", "FEE", "24.00")); + } + + @Test + void testFailure_refundableFee_v06() { + setEppInput("domain_create_fee_refundable.xml", FEE_06_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v11() { + setEppInput("domain_create_fee_refundable.xml", FEE_11_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v12() { + setEppInput("domain_create_fee_refundable.xml", FEE_12_MAP); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_fee_v06() throws Exception { + setEppInput("domain_create_fee.xml", FEE_06_MAP); + persistContactsAndHosts(); + doSuccessfulTest( + "tld", + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.6", "FEE", "24.00")); + } + + @Test + void testSuccess_fee_v11() throws Exception { + setEppInput("domain_create_fee.xml", FEE_11_MAP); + persistContactsAndHosts(); + doSuccessfulTest( + "tld", + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.11", "FEE", "24.00")); + } + + @Test + void testSuccess_fee_v12() throws Exception { + setEppInput("domain_create_fee.xml", FEE_12_MAP); + persistContactsAndHosts(); + doSuccessfulTest( + "tld", + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.12", "FEE", "24.00")); + } + + @Test + void testFailure_eapFee_description_multipleMatch_v06() { + setEppInput( + "domain_create_eap_fee.xml", + ImmutableMap.of( + "FEE_VERSION", + "fee-0.6", + "DESCRIPTION_1", + "create", + "DESCRIPTION_2", + "renew transfer")); + persistContactsAndHosts(); + setEapForTld("tld"); + EppException thrown = assertThrows(FeeDescriptionMultipleMatchesException.class, this::runFlow); + assertThat(thrown).hasMessageThat().contains("RENEW, TRANSFER"); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_unknownCurrency_v12() { + setEppInput( + "domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "fee-0.12", "CURRENCY", "BAD")); + persistContactsAndHosts(); + EppException thrown = assertThrows(UnknownCurrencyEppException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testTieredPricingPromoResponse_v12() throws Exception { + sessionMetadata.setRegistrarId("NewRegistrar"); + setupDefaultTokenWithDiscount("NewRegistrar"); + setEppInput("domain_create_fee.xml", FEE_12_MAP); + persistContactsAndHosts(); + + // Fee in the result should be 24 (create cost of 13 plus renew cost of 11) even though the + // actual cost is lower (due to the tiered pricing promo) + runFlowAssertResponse( + loadFile( + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.12", "FEE", "24.00"))); + // Expected cost is half off the create cost (13/2 == 6.50) plus one full-cost renew (11) + assertThat(Iterables.getOnlyElement(loadAllOf(BillingEvent.class)).getCost()) + .isEqualTo(Money.of(USD, 17.50)); + } + + @Test + void testSuccess_eapFee_multipleEAPfees_doNotAddToExpectedValue_v06() { + setEppInput( + "domain_create_extra_fees.xml", + new ImmutableMap.Builder() + .put("FEE_VERSION", "fee-0.6") + .put("DESCRIPTION_1", "create") + .put("FEE_1", "24") + .put("DESCRIPTION_2", "Early Access Period") + .put("FEE_2", "55") + .put("DESCRIPTION_3", "Early Access Period") + .put("FEE_3", "55") + .build()); + persistContactsAndHosts(); + setEapForTld("tld"); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertThat(thrown).hasMessageThat().contains("expected fee of USD 100.00"); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_eapFee_description_swapped_v06() { + setEppInput( + "domain_create_eap_fee.xml", + ImmutableMap.of( + "FEE_VERSION", + "fee-0.6", + "DESCRIPTION_1", + "Early Access Period", + "DESCRIPTION_2", + "create")); + persistContactsAndHosts(); + setEapForTld("tld"); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertThat(thrown).hasMessageThat().contains("CREATE"); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_doesNotApplyNonPremiumDefaultTokenToPremiumName_v12() throws Exception { + persistContactsAndHosts(); + createTld("example"); + persistResource( + setupDefaultTokenWithDiscount() + .asBuilder() + .setAllowedTlds(ImmutableSet.of("example")) + .build()); + setEppInput("domain_create_premium.xml", FEE_12_MAP); + runFlowAssertResponse( + loadFile( + "domain_create_response_premium.xml", + ImmutableMap.of( + "FEE_VERSION", "fee-0.12", "EXDATE", "2001-04-03T22:00:00.0Z", "FEE", "200.00"))); + assertSuccessfulCreate("example", ImmutableSet.of(), 200); + } + + @Test + void testSuccess_superuserOverridesPremiumNameBlock_v12() throws Exception { + createTld("example"); + setEppInput("domain_create_premium.xml", FEE_12_MAP); + persistContactsAndHosts("net"); + // Modify the Registrar to block premium names. + persistResource(loadRegistrar("TheRegistrar").asBuilder().setBlockPremiumNames(true).build()); + runFlowAssertResponse( + CommitMode.LIVE, + SUPERUSER, + loadFile( + "domain_create_response_premium.xml", + ImmutableMap.of( + "FEE_VERSION", "fee-0.12", "EXDATE", "2001-04-03T22:00:00.0Z", "FEE", "200.00"))); + assertSuccessfulCreate("example", ImmutableSet.of(), 200); + } + + @Test + void testFailure_eapFee_combined_v06() { + setEppInput("domain_create_eap_combined_fee.xml", FEE_06_MAP); + persistContactsAndHosts(); + setEapForTld("tld"); + EppException thrown = assertThrows(FeeDescriptionParseException.class, this::runFlow); + assertThat(thrown).hasMessageThat().contains("No fee description"); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_nonpremiumCreateToken_v06() throws Exception { + createTld("example"); + persistContactsAndHosts(); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(SINGLE_USE) + .setRegistrationBehavior(RegistrationBehavior.NONPREMIUM_CREATE) + .setDomainName("rich.example") + .build()); + setEppInput( + "domain_create_premium_allocationtoken.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.6", "YEARS", "1", "FEE", "13.00")); + runFlowAssertResponse(loadFile("domain_create_nonpremium_token_response.xml", FEE_06_MAP)); + } + + @Test + void testSuccess_eapFee_fullDescription_includingArbitraryExpiryTime_v06() throws Exception { + setEppInput( + "domain_create_eap_fee.xml", + ImmutableMap.of( + "FEE_VERSION", + "fee-0.6", + "DESCRIPTION_1", + "create", + "DESCRIPTION_2", + "Early Access Period, fee expires: 2022-03-01T00:00:00.000Z")); + persistContactsAndHosts(); + setEapForTld("tld"); + doSuccessfulTest("tld", "domain_create_response_eap_fee.xml", FEE_06_MAP); + } + + @Test + void testSuccess_allocationToken_multiYearDiscount_worksForPremiums_v06() throws Exception { + createTld("example"); + persistContactsAndHosts(); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(SINGLE_USE) + .setDomainName("rich.example") + .setDiscountFraction(0.98) + .setDiscountYears(2) + .setDiscountPremiums(true) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().plusMillis(1), TokenStatus.VALID) + .put(clock.nowUtc().plusSeconds(1), TokenStatus.ENDED) + .build()) + .build()); + clock.advanceOneMilli(); + setEppInput( + "domain_create_premium_allocationtoken.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.6", "YEARS", "3", "FEE", "104.00")); + runFlowAssertResponse( + loadFile( + "domain_create_response_premium.xml", + ImmutableMap.of( + "FEE_VERSION", "fee-0.6", "EXDATE", "2002-04-03T22:00:00.0Z", "FEE", "104.00"))); + BillingEvent billingEvent = + Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.class)); + assertThat(billingEvent.getTargetId()).isEqualTo("rich.example"); + // 1yr @ $100 + 2yrs @ $100 * (1 - 0.98) = $104 + assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, 104.00)); + } + + @Test + void testSuccess_eapFee_multipleEAPfees_addToExpectedValue_v06() throws Exception { + setEppInput( + "domain_create_extra_fees.xml", + new ImmutableMap.Builder() + .put("FEE_VERSION", "fee-0.6") + .put("DESCRIPTION_1", "create") + .put("FEE_1", "24") + .put("DESCRIPTION_2", "Early Access Period") + .put("FEE_2", "55") + .put("DESCRIPTION_3", "Early Access Period") + .put("FEE_3", "45") + .build()); + persistContactsAndHosts(); + setEapForTld("tld"); + doSuccessfulTest("tld", "domain_create_response_eap_fee.xml", FEE_06_MAP); + } + + @Test + void testFailure_eapFee_totalAmountNotMatched_v06() { + setEppInput( + "domain_create_extra_fees.xml", + new ImmutableMap.Builder() + .put("FEE_VERSION", "fee-0.6") + .put("DESCRIPTION_1", "create") + .put("FEE_1", "24") + .put("DESCRIPTION_2", "Early Access Period") + .put("FEE_2", "100") + .put("DESCRIPTION_3", "renew") + .put("FEE_3", "55") + .build()); + persistContactsAndHosts(); + setEapForTld("tld"); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertThat(thrown).hasMessageThat().contains("expected total of USD 124.00"); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_premiumAndEap_v06() throws Exception { + createTld("example"); + setEppInput("domain_create_premium_eap.xml", FEE_06_MAP); + persistContactsAndHosts("net"); + persistResource( + Tld.get("example") + .asBuilder() + .setEapFeeSchedule( + ImmutableSortedMap.of( + START_OF_TIME, + Money.of(USD, 0), + clock.nowUtc().minusDays(1), + Money.of(USD, 100), + clock.nowUtc().plusDays(1), + Money.of(USD, 0))) + .build()); + assertMutatingFlow(true); + runFlowAssertResponse( + CommitMode.LIVE, + UserPrivileges.NORMAL, + loadFile("domain_create_response_premium_eap.xml", FEE_06_MAP)); + assertSuccessfulCreate("example", ImmutableSet.of(), 200); + assertNoLordn(); + } + + @Test + void testFailure_premiumBlocked_v06() { + createTld("example"); + setEppInput("domain_create_premium.xml", FEE_06_MAP); + persistContactsAndHosts("net"); + // Modify the Registrar to block premium names. + persistResource(loadRegistrar("TheRegistrar").asBuilder().setBlockPremiumNames(true).build()); + EppException thrown = assertThrows(PremiumNameBlockedException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_allocationToken_singleYearDiscount_worksForPremiums_v06() throws Exception { + createTld("example"); + persistContactsAndHosts(); + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(SINGLE_USE) + .setDomainName("rich.example") + .setDiscountFraction(0.95555) + .setDiscountPremiums(true) + .setTokenStatusTransitions( + ImmutableSortedMap.naturalOrder() + .put(START_OF_TIME, TokenStatus.NOT_STARTED) + .put(clock.nowUtc().plusMillis(1), TokenStatus.VALID) + .put(clock.nowUtc().plusSeconds(1), TokenStatus.ENDED) + .build()) + .build()); + clock.advanceOneMilli(); + setEppInput( + "domain_create_premium_allocationtoken.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.6", "YEARS", "3", "FEE", "204.44")); + runFlowAssertResponse( + loadFile( + "domain_create_response_premium.xml", + ImmutableMap.of( + "FEE_VERSION", "fee-0.6", "EXDATE", "2002-04-03T22:00:00.0Z", "FEE", "204.44"))); + BillingEvent billingEvent = + Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.class)); + assertThat(billingEvent.getTargetId()).isEqualTo("rich.example"); + // 2yrs @ $100 + 1yr @ $100 * (1 - 0.95555) = $204.44 + assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, 204.44)); + } + + @Test + void testTieredPricingPromo_registrarIncluded_noTokenActive_v12() throws Exception { + sessionMetadata.setRegistrarId("NewRegistrar"); + persistActiveDomain("example1.tld"); + + persistResource( + setupDefaultTokenWithDiscount("NewRegistrar") + .asBuilder() + .setTokenStatusTransitions( + ImmutableSortedMap.of( + START_OF_TIME, + TokenStatus.NOT_STARTED, + clock.nowUtc().plusDays(1), + TokenStatus.VALID)) + .build()); + + setEppInput("domain_create_fee.xml", FEE_12_MAP); + persistContactsAndHosts(); + + // The token hasn't started yet, so the cost should be create (13) plus renew (11) + runFlowAssertResponse( + loadFile( + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.12", "FEE", "24.00"))); + assertThat(Iterables.getOnlyElement(loadAllOf(BillingEvent.class)).getCost()) + .isEqualTo(Money.of(USD, 24)); + } + + @Test + void testTieredPricingPromo_registrarNotIncluded_standardResponse_v12() throws Exception { + setupDefaultTokenWithDiscount("NewRegistrar"); + setEppInput("domain_create_fee.xml", FEE_12_MAP); + persistContactsAndHosts(); + + // For a registrar not included in the tiered pricing promo, costs should be 24 + runFlowAssertResponse( + loadFile( + "domain_create_response_fee.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.12", "FEE", "24.00"))); + assertThat(Iterables.getOnlyElement(loadAllOf(BillingEvent.class)).getCost()) + .isEqualTo(Money.of(USD, 24)); + } + + @Test + void testSuccess_nonAnchorTenant_nonPremiumRenewal_v06() throws Exception { + createTld("example"); + AllocationToken token = + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(SINGLE_USE) + .setDomainName("rich.example") + .setRenewalPriceBehavior(NONPREMIUM) + .build()); + persistContactsAndHosts(); + // Creation is still $100 but it'll create a NONPREMIUM renewal + setEppInput( + "domain_create_premium_allocationtoken.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.6", "YEARS", "2", "FEE", "111.00")); + runFlow(); + assertSuccessfulCreate("example", ImmutableSet.of(), token, 111); + } + + @Test + void testSuccess_specifiedRenewalPriceToken_specifiedRecurrencePrice_v06() throws Exception { + createTld("example"); + AllocationToken token = + persistResource( + new AllocationToken.Builder() + .setToken("abc123") + .setTokenType(SINGLE_USE) + .setDomainName("rich.example") + .setRenewalPriceBehavior(SPECIFIED) + .setRenewalPrice(Money.of(USD, 1)) + .build()); + persistContactsAndHosts(); + // Creation is still $100 but it'll create a $1 renewal + setEppInput( + "domain_create_premium_allocationtoken.xml", + ImmutableMap.of("FEE_VERSION", "fee-0.6", "YEARS", "2", "FEE", "101.00")); + runFlow(); + assertSuccessfulCreate("example", ImmutableSet.of(), token, 101, 1); + } +} diff --git a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java index 8c96f30f7..2f0c50c34 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java @@ -209,6 +209,10 @@ class DomainCreateFlowTest extends ResourceFlowTestCase FEE_STD_1_0_MAP = + ImmutableMap.of( + "FEE_VERSION", "epp:fee-1.0", "FEE_NS", "fee1_00", "CURRENCY", "USD", "FEE", "15.00"); + private AllocationToken allocationToken; DomainCreateFlowTest() { @@ -640,132 +644,44 @@ class DomainCreateFlowTest extends ResourceFlowTestCase() - .put("FEE_VERSION", "0.6") + .put("FEE_VERSION", "epp:fee-1.0") .put("DESCRIPTION_1", "create") .put("FEE_1", "24") .put("DESCRIPTION_2", "Early Access Period") @@ -2747,11 +2533,11 @@ class DomainCreateFlowTest extends ResourceFlowTestCase() - .put("FEE_VERSION", "0.6") + .put("FEE_VERSION", "epp:fee-1.0") .put("DESCRIPTION_1", "create") .put("FEE_1", "24") .put("DESCRIPTION_2", "Early Access Period") @@ -2767,11 +2553,11 @@ class DomainCreateFlowTest extends ResourceFlowTestCase() - .put("FEE_VERSION", "0.6") + .put("FEE_VERSION", "epp:fee-1.0") .put("DESCRIPTION_1", "create") .put("FEE_1", "24") .put("DESCRIPTION_2", "Early Access Period") @@ -2781,33 +2567,36 @@ class DomainCreateFlowTest extends ResourceFlowTestCase() + .putAll(FEE_STD_1_0_MAP) + .put("DESCRIPTION_1", "create") + .put("DESCRIPTION_2", "Early Access Period") + .build()); persistContactsAndHosts(); setEapForTld("tld"); - doSuccessfulTest( - "tld", "domain_create_response_eap_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6")); - } - - @Test - void testSuccess_eapFeeApplied_v11() throws Exception { - setEppInput( - "domain_create_eap_fee.xml", - ImmutableMap.of( - "FEE_VERSION", - "0.11", - "DESCRIPTION_1", - "create", - "DESCRIPTION_2", - "Early Access Period")); - persistContactsAndHosts(); - setEapForTld("tld"); - doSuccessfulTest( - "tld", "domain_create_response_eap_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11")); - } - - @Test - void testSuccess_eapFeeApplied_v12() throws Exception { - setEppInput( - "domain_create_eap_fee.xml", - ImmutableMap.of( - "FEE_VERSION", - "0.12", - "DESCRIPTION_1", - "create", - "DESCRIPTION_2", - "Early Access Period")); - persistContactsAndHosts(); - setEapForTld("tld"); - doSuccessfulTest( - "tld", "domain_create_response_eap_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12")); + doSuccessfulTest("tld", "domain_create_response_eap_fee.xml", FEE_STD_1_0_MAP); } @Test @@ -3002,7 +2754,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase { + + private static final DateTime TIME_BEFORE_FLOW = DateTime.parse("2000-06-06T22:00:00.0Z"); + private static final DateTime A_MONTH_AGO = TIME_BEFORE_FLOW.minusMonths(1); + private static final DateTime A_MONTH_FROM_NOW = TIME_BEFORE_FLOW.plusMonths(1); + + private static final ImmutableMap FEE_06_MAP = + ImmutableMap.of("FEE_VERSION", "fee-0.6", "FEE_NS", "fee"); + private static final ImmutableMap FEE_11_MAP = + ImmutableMap.of("FEE_VERSION", "fee-0.11", "FEE_NS", "fee11"); + private static final ImmutableMap FEE_12_MAP = + ImmutableMap.of("FEE_VERSION", "fee-0.12", "FEE_NS", "fee12"); + + private Domain domain; + private DomainHistory earlierHistoryEntry; + + @BeforeEach + void beforeEachomainDeleteFlowOldFeeExtensionsTest() { + clock.setTo(TIME_BEFORE_FLOW); + setEppInput("domain_delete.xml"); + createTld("tld"); + } + + @Test + void testSuccess_renewGracePeriodCredit_v06() throws Exception { + removeServiceExtensionUri(ServiceExtension.FEE_0_11.getUri()); + removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri()); + doSuccessfulTest_noAddGracePeriod("domain_delete_response_pending_fee.xml", FEE_06_MAP); + } + + @Test + void testSuccess_renewGracePeriodCredit_v11() throws Exception { + removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri()); + doSuccessfulTest_noAddGracePeriod("domain_delete_response_pending_fee.xml", FEE_11_MAP); + } + + @Test + void testSuccess_renewGracePeriodCredit_v12() throws Exception { + doSuccessfulTest_noAddGracePeriod("domain_delete_response_pending_fee.xml", FEE_12_MAP); + } + + @Test + void testSuccess_addGracePeriodCredit_v06() throws Exception { + removeServiceExtensionUri(ServiceExtension.FEE_0_11.getUri()); + removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri()); + doAddGracePeriodDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_06_MAP); + } + + @Test + void testSuccess_addGracePeriodCredit_v11() throws Exception { + removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri()); + doAddGracePeriodDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_11_MAP); + } + + @Test + void testSuccess_addGracePeriodCredit_v12() throws Exception { + doAddGracePeriodDeleteTest(GracePeriodStatus.ADD, "domain_delete_response_fee.xml", FEE_12_MAP); + } + + @Test + void testSuccess_autoRenewGracePeriod_v06() throws Exception { + removeServiceExtensionUri(ServiceExtension.FEE_0_11.getUri()); + removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri()); + setUpAutorenewGracePeriod(); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile("domain_delete_response_autorenew_fee.xml", FEE_06_MAP)); + } + + @Test + void testSuccess_autoRenewGracePeriod_v11() throws Exception { + removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri()); + setUpAutorenewGracePeriod(); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile("domain_delete_response_autorenew_fee.xml", FEE_11_MAP)); + } + + @Test + void testSuccess_autoRenewGracePeriod_v12() throws Exception { + setUpAutorenewGracePeriod(); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile("domain_delete_response_autorenew_fee.xml", FEE_12_MAP)); + } + + @Test + void testSuccess_autoRenewGracePeriod_priceChanges_v06() throws Exception { + removeServiceExtensionUri(ServiceExtension.FEE_0_11.getUri()); + removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri()); + persistResource( + Tld.get("tld") + .asBuilder() + .setRenewBillingCostTransitions( + ImmutableSortedMap.of( + START_OF_TIME, + Money.of(USD, 11), + TIME_BEFORE_FLOW.minusDays(5), + Money.of(USD, 20))) + .build()); + setUpAutorenewGracePeriod(); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile("domain_delete_response_autorenew_fee.xml", FEE_06_MAP)); + } + + @Test + void testSuccess_autoRenewGracePeriod_priceChanges_v11() throws Exception { + removeServiceExtensionUri(ServiceExtension.FEE_0_12.getUri()); + persistResource( + Tld.get("tld") + .asBuilder() + .setRenewBillingCostTransitions( + ImmutableSortedMap.of( + START_OF_TIME, + Money.of(USD, 11), + TIME_BEFORE_FLOW.minusDays(5), + Money.of(USD, 20))) + .build()); + setUpAutorenewGracePeriod(); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile("domain_delete_response_autorenew_fee.xml", FEE_11_MAP)); + } + + @Test + void testSuccess_autoRenewGracePeriod_priceChanges_v12() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setRenewBillingCostTransitions( + ImmutableSortedMap.of( + START_OF_TIME, + Money.of(USD, 11), + TIME_BEFORE_FLOW.minusDays(5), + Money.of(USD, 20))) + .build()); + setUpAutorenewGracePeriod(); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile("domain_delete_response_autorenew_fee.xml", FEE_12_MAP)); + } + + @Test + void testSuccess_freeCreation_deletionDuringGracePeriod_v12() throws Exception { + // Deletion during the add grace period should still work even if the credit is 0 + setUpSuccessfulTest(); + BillingEvent graceBillingEvent = + persistResource(createBillingEvent(Reason.CREATE, Money.of(USD, 0))); + setUpGracePeriods( + GracePeriod.forBillingEvent(GracePeriodStatus.ADD, domain.getRepoId(), graceBillingEvent)); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile("domain_delete_response_fee_free_grace_v12.xml")); + } + + private void createReferencedEntities(DateTime expirationTime) throws Exception { + // Persist a linked contact. + Contact contact = persistActiveContact("sh8013"); + domain = + persistResource( + DatabaseHelper.newDomain(getUniqueIdFromCommand()) + .asBuilder() + .setCreationTimeForTest(TIME_BEFORE_FLOW) + .setRegistrant(Optional.of(contact.createVKey())) + .setRegistrationExpirationTime(expirationTime) + .build()); + earlierHistoryEntry = + persistResource( + new DomainHistory.Builder() + .setType(DOMAIN_CREATE) + .setDomain(domain) + .setModificationTime(clock.nowUtc()) + .setRegistrarId(domain.getCreationRegistrarId()) + .build()); + } + + private void setUpSuccessfulTest() throws Exception { + createReferencedEntities(A_MONTH_FROM_NOW); + BillingRecurrence autorenewBillingEvent = + persistResource(createAutorenewBillingEvent("TheRegistrar").build()); + PollMessage.Autorenew autorenewPollMessage = + persistResource(createAutorenewPollMessage("TheRegistrar").build()); + + domain = + persistResource( + domain + .asBuilder() + .setAutorenewBillingEvent(autorenewBillingEvent.createVKey()) + .setAutorenewPollMessage(autorenewPollMessage.createVKey()) + .build()); + + assertMutatingFlow(true); + } + + private void doSuccessfulTest_noAddGracePeriod(String responseFilename) throws Exception { + doSuccessfulTest_noAddGracePeriod(responseFilename, ImmutableMap.of()); + } + + private void doSuccessfulTest_noAddGracePeriod( + String responseFilename, Map substitutions) throws Exception { + // Persist the billing event so it can be retrieved for cancellation generation and checking. + setUpSuccessfulTest(); + BillingEvent renewBillingEvent = + persistResource(createBillingEvent(Reason.RENEW, Money.of(USD, 456))); + setUpGracePeriods( + GracePeriod.forBillingEvent(GracePeriodStatus.RENEW, domain.getRepoId(), renewBillingEvent), + // This grace period has no associated billing event, so it won't cause a cancellation. + GracePeriod.create( + GracePeriodStatus.TRANSFER, + domain.getRepoId(), + TIME_BEFORE_FLOW.plusDays(1), + "NewRegistrar", + null)); + // We should see exactly one poll message, which is for the autorenew 1 month in the future. + assertPollMessages(createAutorenewPollMessage("TheRegistrar").build()); + DateTime expectedExpirationTime = domain.getRegistrationExpirationTime().minusYears(2); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile(responseFilename, substitutions)); + Domain resource = reloadResourceByForeignKey(); + // Check that the domain is in the pending delete state. + assertAboutDomains() + .that(resource) + .hasStatusValue(StatusValue.PENDING_DELETE) + .and() + .hasDeletionTime( + clock + .nowUtc() + .plus(Tld.get("tld").getRedemptionGracePeriodLength()) + .plus(Tld.get("tld").getPendingDeleteLength())) + .and() + .hasExactlyStatusValues(StatusValue.INACTIVE, StatusValue.PENDING_DELETE) + .and() + .hasOneHistoryEntryEachOfTypes(DOMAIN_CREATE, DOMAIN_DELETE); + // We leave the original expiration time unchanged; if the expiration time is before the + // deletion time, that means once it passes the domain will experience a "phantom autorenew" + // where the expirationTime advances and the grace period appears, but since the delete flow + // closed the autorenew recurrences immediately, there are no other autorenew effects. + assertAboutDomains().that(resource).hasRegistrationExpirationTime(expectedExpirationTime); + assertLastHistoryContainsResource(resource); + // All existing grace periods that were for billable actions should cause cancellations. + assertAutorenewClosedAndCancellationCreatedFor( + renewBillingEvent, getOnlyHistoryEntryOfType(resource, DOMAIN_DELETE, DomainHistory.class)); + // All existing grace periods should be gone, and a new REDEMPTION one should be added. + assertThat(resource.getGracePeriods()) + .containsExactly( + GracePeriod.create( + GracePeriodStatus.REDEMPTION, + domain.getRepoId(), + clock.nowUtc().plus(Tld.get("tld").getRedemptionGracePeriodLength()), + "TheRegistrar", + null, + resource.getGracePeriods().iterator().next().getGracePeriodId())); + assertDeletionPollMessageFor(resource, "Domain deleted."); + } + + private void assertDeletionPollMessageFor(Domain domain, String expectedMessage) { + // There should be a future poll message at the deletion time. The previous autorenew poll + // message should now be deleted. + assertAboutDomains().that(domain).hasDeletePollMessage(); + DateTime deletionTime = domain.getDeletionTime(); + assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).isEmpty(); + assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(1); + assertThat(domain.getDeletePollMessage()) + .isEqualTo(getOnlyPollMessage("TheRegistrar").createVKey()); + PollMessage.OneTime deletePollMessage = loadByKey(domain.getDeletePollMessage()); + assertThat(deletePollMessage.getMsg()).isEqualTo(expectedMessage); + } + + private void setUpGracePeriods(GracePeriod... gracePeriods) { + domain = + persistResource( + domain.asBuilder().setGracePeriods(ImmutableSet.copyOf(gracePeriods)).build()); + } + + private void assertAutorenewClosedAndCancellationCreatedFor( + BillingEvent graceBillingEvent, DomainHistory historyEntryDomainDelete) { + assertAutorenewClosedAndCancellationCreatedFor( + graceBillingEvent, historyEntryDomainDelete, clock.nowUtc()); + } + + private void assertAutorenewClosedAndCancellationCreatedFor( + BillingEvent graceBillingEvent, DomainHistory historyEntryDomainDelete, DateTime eventTime) { + assertBillingEvents( + createAutorenewBillingEvent("TheRegistrar").setRecurrenceEndTime(eventTime).build(), + graceBillingEvent, + new BillingCancellation.Builder() + .setReason(graceBillingEvent.getReason()) + .setTargetId("example.tld") + .setRegistrarId("TheRegistrar") + .setEventTime(eventTime) + .setBillingTime(TIME_BEFORE_FLOW.plusDays(1)) + .setBillingEvent(graceBillingEvent.createVKey()) + .setDomainHistory(historyEntryDomainDelete) + .build()); + } + + private BillingRecurrence.Builder createAutorenewBillingEvent(String registrarId) { + return new BillingRecurrence.Builder() + .setReason(Reason.RENEW) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId("example.tld") + .setRegistrarId(registrarId) + .setEventTime(A_MONTH_FROM_NOW) + .setRecurrenceEndTime(END_OF_TIME) + .setDomainHistory(earlierHistoryEntry); + } + + private PollMessage.Autorenew.Builder createAutorenewPollMessage(String registrarId) { + return new PollMessage.Autorenew.Builder() + .setTargetId("example.tld") + .setRegistrarId(registrarId) + .setEventTime(A_MONTH_FROM_NOW) + .setAutorenewEndTime(END_OF_TIME) + .setHistoryEntry(earlierHistoryEntry); + } + + private BillingEvent createBillingEvent(Reason reason, Money cost) { + return new BillingEvent.Builder() + .setReason(reason) + .setTargetId("example.tld") + .setRegistrarId("TheRegistrar") + .setCost(cost) + .setPeriodYears(2) + .setEventTime(TIME_BEFORE_FLOW.minusDays(4)) + .setBillingTime(TIME_BEFORE_FLOW.plusDays(1)) + .setDomainHistory(earlierHistoryEntry) + .build(); + } + + private void doAddGracePeriodDeleteTest( + GracePeriodStatus gracePeriodStatus, String responseFilename) throws Exception { + doAddGracePeriodDeleteTest(gracePeriodStatus, responseFilename, ImmutableMap.of()); + } + + private void doAddGracePeriodDeleteTest( + GracePeriodStatus gracePeriodStatus, + String responseFilename, + Map substitutions) + throws Exception { + // Persist the billing event so it can be retrieved for cancellation generation and checking. + setUpSuccessfulTest(); + BillingEvent graceBillingEvent = + persistResource(createBillingEvent(Reason.CREATE, Money.of(USD, 123))); + setUpGracePeriods( + GracePeriod.forBillingEvent(gracePeriodStatus, domain.getRepoId(), graceBillingEvent)); + // We should see exactly one poll message, which is for the autorenew 1 month in the future. + assertPollMessages(createAutorenewPollMessage("TheRegistrar").build()); + clock.advanceOneMilli(); + runFlowAssertResponse(loadFile(responseFilename, substitutions)); + // Check that the domain is fully deleted. + assertThat(reloadResourceByForeignKey()).isNull(); + // The add grace period is for a billable action, so it should trigger a cancellation. + assertAutorenewClosedAndCancellationCreatedFor( + graceBillingEvent, getOnlyHistoryEntryOfType(domain, DOMAIN_DELETE, DomainHistory.class)); + assertDomainDnsRequests("example.tld"); + // There should be no poll messages. The previous autorenew poll message should now be deleted. + assertThat(getPollMessages("TheRegistrar")).isEmpty(); + } + + private void setUpAutorenewGracePeriod() throws Exception { + createReferencedEntities(A_MONTH_AGO.plusYears(1)); + BillingRecurrence autorenewBillingEvent = + persistResource( + createAutorenewBillingEvent("TheRegistrar").setEventTime(A_MONTH_AGO).build()); + PollMessage.Autorenew autorenewPollMessage = + persistResource( + createAutorenewPollMessage("TheRegistrar").setEventTime(A_MONTH_AGO).build()); + domain = + persistResource( + domain + .asBuilder() + .setGracePeriods( + ImmutableSet.of( + GracePeriod.createForRecurrence( + GracePeriodStatus.AUTO_RENEW, + domain.getRepoId(), + A_MONTH_AGO.plusDays(45), + "TheRegistrar", + autorenewBillingEvent.createVKey()))) + .setAutorenewBillingEvent(autorenewBillingEvent.createVKey()) + .setAutorenewPollMessage(autorenewPollMessage.createVKey()) + .build()); + assertMutatingFlow(true); + } +} diff --git a/core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java index c84d7b012..8f83d520c 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java @@ -86,7 +86,6 @@ import google.registry.model.domain.Domain; import google.registry.model.domain.DomainHistory; import google.registry.model.domain.GracePeriod; import google.registry.model.domain.rgp.GracePeriodStatus; -import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension; import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.Trid; import google.registry.model.host.Host; @@ -122,12 +121,8 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase FEE_06_MAP = - ImmutableMap.of("FEE_VERSION", "0.6", "FEE_NS", "fee"); - private static final ImmutableMap FEE_11_MAP = - ImmutableMap.of("FEE_VERSION", "0.11", "FEE_NS", "fee11"); - private static final ImmutableMap FEE_12_MAP = - ImmutableMap.of("FEE_VERSION", "0.12", "FEE_NS", "fee12"); + private static final ImmutableMap FEE_STD_1_0_MAP = + ImmutableMap.of("FEE_VERSION", "epp:fee-1.0", "FEE_NS", "fee1_00"); DomainDeleteFlowTest() { setEppInput("domain_delete.xml"); @@ -396,24 +391,9 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase { + + /** + * The domain_info_fee.xml default substitutions common to most tests. + * + *

It doesn't set a default value to the COMMAND and PERIOD keys, because they are different in + * every test. + */ + private static final ImmutableMap SUBSTITUTION_BASE = + ImmutableMap.of( + "NAME", "example.tld", + "CURRENCY", "USD", + "UNIT", "y"); + + private static final Pattern OK_PATTERN = Pattern.compile("\"ok\""); + + private Host host1; + private Host host2; + private Host host3; + private Domain domain; + + @BeforeEach + void beforeEachDomainInfoFlowOldFeeExtensionsTest() { + setEppInput("domain_info.xml"); + clock.setTo(DateTime.parse("2005-03-03T22:00:00.000Z")); + sessionMetadata.setRegistrarId("NewRegistrar"); + createTld("tld"); + persistResource( + JpaTransactionManagerExtension.makeRegistrar1() + .asBuilder() + .setRegistrarId("ClientZ") + .build()); + } + + private void persistTestEntities(String domainName, boolean inactive) { + host1 = persistActiveHost("ns1.example.tld"); + host2 = persistActiveHost("ns1.example.net"); + domain = + persistResource( + new Domain.Builder() + .setDomainName(domainName) + .setRepoId("2FF-TLD") + .setPersistedCurrentSponsorRegistrarId("NewRegistrar") + .setCreationRegistrarId("TheRegistrar") + .setLastEppUpdateRegistrarId("NewRegistrar") + .setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z")) + .setLastEppUpdateTime(DateTime.parse("1999-12-03T09:00:00.0Z")) + .setLastTransferTime(DateTime.parse("2000-04-08T09:00:00.0Z")) + .setRegistrationExpirationTime(DateTime.parse("2005-04-03T22:00:00.0Z")) + .setNameservers( + inactive ? null : ImmutableSet.of(host1.createVKey(), host2.createVKey())) + .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("2fooBAR"))) + .build()); + // Set the superordinate domain of ns1.example.com to example.com. In reality, this would have + // happened in the flow that created it, but here we just overwrite it in the database. + host1 = persistResource(host1.asBuilder().setSuperordinateDomain(domain.createVKey()).build()); + // Create a subordinate host that is not delegated to by anyone. + host3 = + persistResource( + new Host.Builder() + .setHostName("ns2.example.tld") + .setRepoId("3FF-TLD") + .setSuperordinateDomain(domain.createVKey()) + .build()); + // Add the subordinate host keys to the existing domain. + domain = + persistResource( + domain + .asBuilder() + .setSubordinateHosts(ImmutableSet.of(host1.getHostName(), host3.getHostName())) + .build()); + } + + private void persistTestEntities(boolean inactive) { + persistTestEntities("example.tld", inactive); + } + + private void doSuccessfulTest( + String expectedXmlFilename, + boolean inactive, + ImmutableMap substitutions, + boolean expectHistoryAndBilling) + throws Exception { + assertMutatingFlow(true); + String expected = + loadFile(expectedXmlFilename, updateSubstitutions(substitutions, "ROID", "2FF-TLD")); + if (inactive) { + expected = OK_PATTERN.matcher(expected).replaceAll("\"inactive\""); + } + runFlowAssertResponse(expected); + if (!expectHistoryAndBilling) { + assertNoHistory(); + assertNoBillingEvents(); + } + } + + private void doSuccessfulTest(String expectedXmlFilename, boolean inactive) throws Exception { + doSuccessfulTest(expectedXmlFilename, inactive, ImmutableMap.of(), false); + } + + private void doSuccessfulTest(String expectedXmlFilename) throws Exception { + persistTestEntities(false); + doSuccessfulTest(expectedXmlFilename, false); + } + + private void doSuccessfulTestNoNameservers(String expectedXmlFilename) throws Exception { + persistTestEntities(true); + 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 testFeeExtension_restoreCommand_pendingDelete_withRenewal() throws Exception { + createTld("example"); + setEppInput( + "domain_info_fee.xml", + updateSubstitutions( + SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "restore", "PERIOD", "1")); + persistTestEntities("rich.example", false); + setUpBillingEventForExistingDomain(); + persistResource( + domain + .asBuilder() + .setDeletionTime(clock.nowUtc().plusDays(25)) + .setRegistrationExpirationTime(clock.nowUtc().minusDays(1)) + .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) + .build()); + doSuccessfulTest( + "domain_info_fee_restore_response_with_renewal.xml", false, ImmutableMap.of(), true); + } + + /** + * Test create command. Fee extension version 6 is the only one which supports fee extensions on + * info commands and responses, so we don't need to test the other versions. + */ + @Test + void testFeeExtension_createCommand() throws Exception { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "create", "PERIOD", "2")); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + doSuccessfulTest( + "domain_info_fee_response.xml", + false, + ImmutableMap.of( + "COMMAND", "create", + "DESCRIPTION", "create", + "PERIOD", "2", + "FEE", "24.00"), + true); + } + + /** Test renew command. */ + @Test + void testFeeExtension_renewCommand() throws Exception { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "renew", "PERIOD", "2")); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + doSuccessfulTest( + "domain_info_fee_response.xml", + false, + ImmutableMap.of( + "COMMAND", "renew", + "DESCRIPTION", "renew", + "PERIOD", "2", + "FEE", "22.00"), + true); + } + + /** Test transfer command. */ + @Test + void testFeeExtension_transferCommand() throws Exception { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "transfer", "PERIOD", "1")); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + doSuccessfulTest( + "domain_info_fee_response.xml", + false, + ImmutableMap.of( + "COMMAND", "transfer", + "DESCRIPTION", "renew", + "PERIOD", "1", + "FEE", "11.00"), + true); + } + + /** Test restore command. */ + @Test + void testFeeExtension_restoreCommand() throws Exception { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "restore", "PERIOD", "1")); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + doSuccessfulTest("domain_info_fee_restore_response.xml", false, ImmutableMap.of(), true); + } + + @Test + void testFeeExtension_restoreCommand_pendingDelete_noRenewal() throws Exception { + setEppInput( + "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, ImmutableMap.of(), true); + } + + /** Test create command on a premium label. */ + @Test + void testFeeExtension_createCommandPremium() throws Exception { + createTld("example"); + setEppInput( + "domain_info_fee.xml", + updateSubstitutions( + SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "create", "PERIOD", "1")); + persistTestEntities("rich.example", false); + setUpBillingEventForExistingDomain(); + doSuccessfulTest( + "domain_info_fee_premium_response.xml", + false, + ImmutableMap.of("COMMAND", "create", "DESCRIPTION", "create"), + true); + } + + /** Test renew command on a premium label. */ + @Test + void testFeeExtension_renewCommandPremium() throws Exception { + createTld("example"); + setEppInput( + "domain_info_fee.xml", + updateSubstitutions( + SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "renew", "PERIOD", "1")); + persistTestEntities("rich.example", false); + setUpBillingEventForExistingDomain(); + doSuccessfulTest( + "domain_info_fee_premium_response.xml", + false, + ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew"), + true); + } + + @Test + void testFeeExtension_renewCommandPremium_anchorTenant() throws Exception { + createTld("tld"); + persistResource( + Tld.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.00", "PERIOD", "1"), + true); + } + + @Test + void testFeeExtension_renewCommandPremium_internalRegistration() throws Exception { + createTld("tld"); + persistResource( + Tld.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.00", "PERIOD", "1"), + true); + } + + @Test + void testFeeExtension_renewCommandPremium_anchorTenant_multiYear() throws Exception { + createTld("tld"); + persistResource( + Tld.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.00", "PERIOD", "3"), + true); + } + + @Test + void testFeeExtension_renewCommandPremium_internalRegistration_multiYear() throws Exception { + createTld("tld"); + persistResource( + Tld.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.00", "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.00", "PERIOD", "1"), + true); + } + + /** Test transfer command on a premium label. */ + @Test + void testFeeExtension_transferCommandPremium() throws Exception { + createTld("example"); + setEppInput( + "domain_info_fee.xml", + updateSubstitutions( + SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "transfer", "PERIOD", "1")); + persistTestEntities("rich.example", false); + setUpBillingEventForExistingDomain(); + doSuccessfulTest( + "domain_info_fee_premium_response.xml", + false, + ImmutableMap.of("COMMAND", "transfer", "DESCRIPTION", "renew"), + true); + } + + /** Test restore command on a premium label. */ + @Test + void testFeeExtension_restoreCommandPremium() throws Exception { + createTld("example"); + setEppInput( + "domain_info_fee.xml", + updateSubstitutions( + SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "restore", "PERIOD", "1")); + persistTestEntities("rich.example", false); + setUpBillingEventForExistingDomain(); + doSuccessfulTest( + "domain_info_fee_restore_premium_response.xml", false, ImmutableMap.of(), true); + } + + /** Test setting the currency explicitly to a wrong value. */ + @Test + void testFeeExtension_wrongCurrency() { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions( + SUBSTITUTION_BASE, "COMMAND", "create", "CURRENCY", "EUR", "PERIOD", "1")); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + /** Test requesting a period that isn't in years. */ + @Test + void testFeeExtension_periodNotInYears() { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "create", "PERIOD", "2", "UNIT", "m")); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + /** Test a command that specifies a phase. */ + @Test + void testFeeExtension_commandPhase() { + setEppInput("domain_info_fee_command_phase.xml"); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + /** Test a command that specifies a subphase. */ + @Test + void testFeeExtension_commandSubphase() { + setEppInput("domain_info_fee_command_subphase.xml"); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + /** Test a restore for more than one year. */ + @Test + void testFeeExtension_multiyearRestore() { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "restore", "PERIOD", "2")); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + /** Test a transfer for more than one year. */ + @Test + void testFeeExtension_multiyearTransfer() { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "transfer", "PERIOD", "2")); + persistTestEntities(false); + setUpBillingEventForExistingDomain(); + EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFeeExtension_unknownCurrency() { + setEppInput( + "domain_info_fee.xml", + updateSubstitutions( + SUBSTITUTION_BASE, "COMMAND", "create", "CURRENCY", "BAD", "PERIOD", "1")); + EppException thrown = assertThrows(UnknownCurrencyEppException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } +} diff --git a/core/src/test/java/google/registry/flows/domain/DomainInfoFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainInfoFlowTest.java index 5a4ac81e6..2f6d2ed47 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainInfoFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainInfoFlowTest.java @@ -17,15 +17,12 @@ 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.BillingBase.RenewalPriceBehavior.DEFAULT; -import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM; -import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED; import static google.registry.model.eppcommon.EppXmlTransformer.marshal; import static google.registry.model.tld.Tld.TldState.QUIET_PERIOD; import static google.registry.testing.DatabaseHelper.assertNoBillingEvents; import static google.registry.testing.DatabaseHelper.createTld; 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; @@ -41,15 +38,9 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; import google.registry.flows.EppException; import google.registry.flows.FlowUtils.NotLoggedInException; -import google.registry.flows.FlowUtils.UnknownCurrencyEppException; import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException; import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; -import google.registry.flows.domain.DomainFlowUtils.BadPeriodUnitException; -import google.registry.flows.domain.DomainFlowUtils.CurrencyUnitMismatchException; -import google.registry.flows.domain.DomainFlowUtils.FeeChecksDontSupportPhasesException; -import google.registry.flows.domain.DomainFlowUtils.RestoresAreAlwaysForOneYearException; -import google.registry.flows.domain.DomainFlowUtils.TransfersAreAlwaysForOneYearException; import google.registry.model.billing.BillingBase.Flag; import google.registry.model.billing.BillingBase.Reason; import google.registry.model.billing.BillingBase.RenewalPriceBehavior; @@ -586,353 +577,6 @@ class DomainInfoFlowTest extends ResourceFlowTestCase { assertAboutEppExceptions().that(thrown).marshalsToXml(); } - /** - * Test create command. Fee extension version 6 is the only one which supports fee extensions on - * info commands and responses, so we don't need to test the other versions. - */ - @Test - void testFeeExtension_createCommand() throws Exception { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "create", "PERIOD", "2")); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - doSuccessfulTest( - "domain_info_fee_response.xml", - false, - ImmutableMap.of( - "COMMAND", "create", - "DESCRIPTION", "create", - "PERIOD", "2", - "FEE", "24.00"), - true); - } - - /** Test renew command. */ - @Test - void testFeeExtension_renewCommand() throws Exception { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "renew", "PERIOD", "2")); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - doSuccessfulTest( - "domain_info_fee_response.xml", - false, - ImmutableMap.of( - "COMMAND", "renew", - "DESCRIPTION", "renew", - "PERIOD", "2", - "FEE", "22.00"), - true); - } - - /** Test transfer command. */ - @Test - void testFeeExtension_transferCommand() throws Exception { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "transfer", "PERIOD", "1")); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - doSuccessfulTest( - "domain_info_fee_response.xml", - false, - ImmutableMap.of( - "COMMAND", "transfer", - "DESCRIPTION", "renew", - "PERIOD", "1", - "FEE", "11.00"), - true); - } - - /** Test restore command. */ - @Test - void testFeeExtension_restoreCommand() throws Exception { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "restore", "PERIOD", "1")); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - doSuccessfulTest("domain_info_fee_restore_response.xml", false, ImmutableMap.of(), true); - } - - @Test - void testFeeExtension_restoreCommand_pendingDelete_noRenewal() throws Exception { - setEppInput( - "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, ImmutableMap.of(), true); - } - - @Test - void testFeeExtension_restoreCommand_pendingDelete_withRenewal() throws Exception { - createTld("example"); - setEppInput( - "domain_info_fee.xml", - updateSubstitutions( - SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "restore", "PERIOD", "1")); - persistTestEntities("rich.example", false); - setUpBillingEventForExistingDomain(); - persistResource( - domain - .asBuilder() - .setDeletionTime(clock.nowUtc().plusDays(25)) - .setRegistrationExpirationTime(clock.nowUtc().minusDays(1)) - .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) - .build()); - doSuccessfulTest( - "domain_info_fee_restore_response_with_renewal.xml", false, ImmutableMap.of(), true); - } - - /** Test create command on a premium label. */ - @Test - void testFeeExtension_createCommandPremium() throws Exception { - createTld("example"); - setEppInput( - "domain_info_fee.xml", - updateSubstitutions( - SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "create", "PERIOD", "1")); - persistTestEntities("rich.example", false); - setUpBillingEventForExistingDomain(); - doSuccessfulTest( - "domain_info_fee_premium_response.xml", - false, - ImmutableMap.of("COMMAND", "create", "DESCRIPTION", "create"), - true); - } - - /** Test renew command on a premium label. */ - @Test - void testFeeExtension_renewCommandPremium() throws Exception { - createTld("example"); - setEppInput( - "domain_info_fee.xml", - updateSubstitutions( - SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "renew", "PERIOD", "1")); - persistTestEntities("rich.example", false); - setUpBillingEventForExistingDomain(); - doSuccessfulTest( - "domain_info_fee_premium_response.xml", - false, - ImmutableMap.of("COMMAND", "renew", "DESCRIPTION", "renew"), - true); - } - - @Test - void testFeeExtension_renewCommandPremium_anchorTenant() throws Exception { - createTld("tld"); - persistResource( - Tld.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.00", "PERIOD", "1"), - true); - } - - @Test - void testFeeExtension_renewCommandPremium_internalRegistration() throws Exception { - createTld("tld"); - persistResource( - Tld.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.00", "PERIOD", "1"), - true); - } - - @Test - void testFeeExtension_renewCommandPremium_anchorTenant_multiYear() throws Exception { - createTld("tld"); - persistResource( - Tld.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.00", "PERIOD", "3"), - true); - } - - @Test - void testFeeExtension_renewCommandPremium_internalRegistration_multiYear() throws Exception { - createTld("tld"); - persistResource( - Tld.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.00", "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.00", "PERIOD", "1"), - true); - } - - /** Test transfer command on a premium label. */ - @Test - void testFeeExtension_transferCommandPremium() throws Exception { - createTld("example"); - setEppInput( - "domain_info_fee.xml", - updateSubstitutions( - SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "transfer", "PERIOD", "1")); - persistTestEntities("rich.example", false); - setUpBillingEventForExistingDomain(); - doSuccessfulTest( - "domain_info_fee_premium_response.xml", - false, - ImmutableMap.of("COMMAND", "transfer", "DESCRIPTION", "renew"), - true); - } - - /** Test restore command on a premium label. */ - @Test - void testFeeExtension_restoreCommandPremium() throws Exception { - createTld("example"); - setEppInput( - "domain_info_fee.xml", - updateSubstitutions( - SUBSTITUTION_BASE, "NAME", "rich.example", "COMMAND", "restore", "PERIOD", "1")); - persistTestEntities("rich.example", false); - setUpBillingEventForExistingDomain(); - doSuccessfulTest( - "domain_info_fee_restore_premium_response.xml", false, ImmutableMap.of(), true); - } - - /** Test setting the currency explicitly to a wrong value. */ - @Test - void testFeeExtension_wrongCurrency() { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions( - SUBSTITUTION_BASE, "COMMAND", "create", "CURRENCY", "EUR", "PERIOD", "1")); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFeeExtension_unknownCurrency() { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions( - SUBSTITUTION_BASE, "COMMAND", "create", "CURRENCY", "BAD", "PERIOD", "1")); - EppException thrown = assertThrows(UnknownCurrencyEppException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - /** Test requesting a period that isn't in years. */ - @Test - void testFeeExtension_periodNotInYears() { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "create", "PERIOD", "2", "UNIT", "m")); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - /** Test a command that specifies a phase. */ - @Test - void testFeeExtension_commandPhase() { - setEppInput("domain_info_fee_command_phase.xml"); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - /** Test a command that specifies a subphase. */ - @Test - void testFeeExtension_commandSubphase() { - setEppInput("domain_info_fee_command_subphase.xml"); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - /** Test a restore for more than one year. */ - @Test - void testFeeExtension_multiyearRestore() { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "restore", "PERIOD", "2")); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - /** Test a transfer for more than one year. */ - @Test - void testFeeExtension_multiyearTransfer() { - setEppInput( - "domain_info_fee.xml", - updateSubstitutions(SUBSTITUTION_BASE, "COMMAND", "transfer", "PERIOD", "2")); - persistTestEntities(false); - setUpBillingEventForExistingDomain(); - EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - @Test void testIcannActivityReportField_getsLogged() throws Exception { persistTestEntities(false); diff --git a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowOldFeeExtensionsTest.java b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowOldFeeExtensionsTest.java new file mode 100644 index 000000000..dedb43016 --- /dev/null +++ b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowOldFeeExtensionsTest.java @@ -0,0 +1,827 @@ +// Copyright 2026 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.flows.domain; + +import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.DEFAULT; +import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM; +import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED; +import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO; +import static google.registry.testing.DatabaseHelper.assertBillingEvents; +import static google.registry.testing.DatabaseHelper.assertPollMessages; +import static google.registry.testing.DatabaseHelper.createTld; +import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType; +import static google.registry.testing.DatabaseHelper.loadByKey; +import static google.registry.testing.DatabaseHelper.loadRegistrar; +import static google.registry.testing.DatabaseHelper.persistPremiumList; +import static google.registry.testing.DatabaseHelper.persistResource; +import static google.registry.testing.DatabaseHelper.persistResources; +import static google.registry.testing.DomainSubject.assertAboutDomains; +import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; +import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries; +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.EUR; +import static org.joda.money.CurrencyUnit.USD; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.Iterables; +import google.registry.flows.EppException; +import google.registry.flows.domain.DomainFlowUtils.CurrencyUnitMismatchException; +import google.registry.flows.domain.DomainFlowUtils.CurrencyValueScaleException; +import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException; +import google.registry.flows.domain.DomainFlowUtils.UnsupportedFeeAttributeException; +import google.registry.model.billing.BillingBase.Flag; +import google.registry.model.billing.BillingBase.Reason; +import google.registry.model.billing.BillingBase.RenewalPriceBehavior; +import google.registry.model.billing.BillingEvent; +import google.registry.model.billing.BillingRecurrence; +import google.registry.model.domain.Domain; +import google.registry.model.domain.DomainHistory; +import google.registry.model.domain.GracePeriod; +import google.registry.model.domain.rgp.GracePeriodStatus; +import google.registry.model.domain.token.AllocationToken; +import google.registry.model.eppcommon.StatusValue; +import google.registry.model.poll.PollMessage; +import google.registry.model.reporting.HistoryEntry; +import google.registry.model.tld.Tld; +import google.registry.testing.DatabaseHelper; +import java.util.Map; +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.Test; + +/** Tests for {@link DomainRenewFlow} that use the old fee extensions (0.6, 0.11, 0.12). */ +public class DomainRenewFlowOldFeeExtensionsTest + extends ProductionSimulatingFeeExtensionsTest { + + private static final ImmutableMap FEE_BASE_MAP = + ImmutableMap.of( + "NAME", "example.tld", + "PERIOD", "5", + "EX_DATE", "2005-04-03T22:00:00.0Z", + "FEE", "55.00", + "CURRENCY", "USD"); + + private static final ImmutableMap FEE_06_MAP = + updateSubstitutions(FEE_BASE_MAP, "FEE_VERSION", "fee-0.6", "FEE_NS", "fee"); + private static final ImmutableMap FEE_11_MAP = + updateSubstitutions(FEE_BASE_MAP, "FEE_VERSION", "fee-0.11", "FEE_NS", "fee11"); + private static final ImmutableMap FEE_12_MAP = + updateSubstitutions(FEE_BASE_MAP, "FEE_VERSION", "fee-0.12", "FEE_NS", "fee12"); + + private final DateTime expirationTime = DateTime.parse("2000-04-03T22:00:00.0Z"); + + @BeforeEach + void beforeEachDomainRenewFlowOldFeeExtensionsTest() { + clock.setTo(expirationTime.minusMillis(20)); + createTld("tld"); + persistResource( + loadRegistrar("TheRegistrar") + .asBuilder() + .setBillingAccountMap(ImmutableMap.of(USD, "123", EUR, "567")) + .build()); + setEppInput("domain_renew.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "5")); + } + + private void persistDomain(StatusValue... statusValues) throws Exception { + persistDomain(DEFAULT, null, statusValues); + } + + private void persistDomain( + RenewalPriceBehavior renewalPriceBehavior, + @Nullable Money renewalPrice, + StatusValue... statusValues) + throws Exception { + Domain domain = DatabaseHelper.newDomain(getUniqueIdFromCommand()); + try { + DomainHistory historyEntryDomainCreate = + new DomainHistory.Builder() + .setDomain(domain) + .setType(HistoryEntry.Type.DOMAIN_CREATE) + .setModificationTime(clock.nowUtc()) + .setRegistrarId(domain.getCreationRegistrarId()) + .build(); + BillingRecurrence autorenewEvent = + new BillingRecurrence.Builder() + .setReason(Reason.RENEW) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId("TheRegistrar") + .setEventTime(expirationTime) + .setRecurrenceEndTime(END_OF_TIME) + .setDomainHistory(historyEntryDomainCreate) + .setRenewalPriceBehavior(renewalPriceBehavior) + .setRenewalPrice(renewalPrice) + .build(); + PollMessage.Autorenew autorenewPollMessage = + new PollMessage.Autorenew.Builder() + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId("TheRegistrar") + .setEventTime(expirationTime) + .setAutorenewEndTime(END_OF_TIME) + .setMsg("Domain was auto-renewed.") + .setHistoryEntry(historyEntryDomainCreate) + .build(); + Domain newDomain = + domain + .asBuilder() + .setRegistrationExpirationTime(expirationTime) + .setStatusValues(ImmutableSet.copyOf(statusValues)) + .setAutorenewBillingEvent(autorenewEvent.createVKey()) + .setAutorenewPollMessage(autorenewPollMessage.createVKey()) + .build(); + persistResources( + ImmutableSet.of( + historyEntryDomainCreate, autorenewEvent, + autorenewPollMessage, newDomain)); + } catch (Exception e) { + throw new RuntimeException("Error persisting domain", e); + } + clock.advanceOneMilli(); + } + + @Test + void testFailure_wrongFeeAmount_v06() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_06_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + persistDomain(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmount_v11() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_11_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + persistDomain(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmount_v12() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_12_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + persistDomain(); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongCurrency_v06() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_06_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setCurrency(EUR) + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 13))) + .setRestoreBillingCost(Money.of(EUR, 11)) + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 7))) + .setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(EUR))) + .setRegistryLockOrUnlockBillingCost(Money.of(EUR, 20)) + .setServerStatusChangeBillingCost(Money.of(EUR, 19)) + .build()); + persistDomain(); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongCurrency_v11() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_11_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setCurrency(EUR) + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 13))) + .setRestoreBillingCost(Money.of(EUR, 11)) + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 7))) + .setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(EUR))) + .setRegistryLockOrUnlockBillingCost(Money.of(EUR, 20)) + .setServerStatusChangeBillingCost(Money.of(EUR, 19)) + .build()); + persistDomain(); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongCurrency_v12() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_12_MAP); + persistResource( + Tld.get("tld") + .asBuilder() + .setCurrency(EUR) + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 13))) + .setRestoreBillingCost(Money.of(EUR, 11)) + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 7))) + .setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(EUR))) + .setRegistryLockOrUnlockBillingCost(Money.of(EUR, 20)) + .setServerStatusChangeBillingCost(Money.of(EUR, 19)) + .build()); + persistDomain(); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v06() throws Exception { + setEppInput("domain_renew_fee_bad_scale.xml", FEE_06_MAP); + persistDomain(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v11() throws Exception { + setEppInput("domain_renew_fee_bad_scale.xml", FEE_11_MAP); + persistDomain(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v12() throws Exception { + setEppInput("domain_renew_fee_bad_scale.xml", FEE_12_MAP); + persistDomain(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_doesNotApplyNonPremiumDefaultTokenToPremiumName_v06() throws Exception { + ImmutableMap customFeeMap = updateSubstitutions(FEE_06_MAP, "FEE", "500"); + setEppInput("domain_renew_fee.xml", customFeeMap); + persistDomain(); + AllocationToken defaultToken1 = + persistResource( + new AllocationToken.Builder() + .setToken("aaaaa") + .setTokenType(DEFAULT_PROMO) + .setDiscountFraction(0.5) + .setDiscountYears(1) + .setAllowedTlds(ImmutableSet.of("tld")) + .build()); + persistResource( + Tld.get("tld") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) + .setPremiumList(persistPremiumList("tld", USD, "example,USD 100")) + .build()); + runFlowAssertResponse( + loadFile( + "domain_renew_response_fee.xml", + ImmutableMap.of( + "NAME", + "example.tld", + "PERIOD", + "5", + "EX_DATE", + "2005-04-03T22:00:00.0Z", + "FEE", + "500.00", + "CURRENCY", + "USD", + "FEE_VERSION", + "fee-0.6", + "FEE_NS", + "fee"))); + BillingEvent billingEvent = + Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.class)); + assertThat(billingEvent.getTargetId()).isEqualTo("example.tld"); + assertThat(billingEvent.getAllocationToken()).isEmpty(); + } + + @Test + void testSuccess_internalRegiration_premiumDomain_v06() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setPremiumList(persistPremiumList("tld", USD, "example,USD 100")) + .build()); + persistDomain(SPECIFIED, Money.of(USD, 2)); + setRegistrarIdForFlow("NewRegistrar"); + ImmutableMap customFeeMap = updateSubstitutions(FEE_06_MAP, "FEE", "10.00"); + setEppInput("domain_renew_fee.xml", customFeeMap); + doSuccessfulTest( + "domain_renew_response_fee.xml", + 5, + "NewRegistrar", + UserPrivileges.SUPERUSER, + customFeeMap, + Money.of(USD, 10), + SPECIFIED, + Money.of(USD, 2)); + } + + @Test + void testSuccess_wrongFeeAmountTooHigh_defaultToken_v06() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_06_MAP); + persistDomain(); + AllocationToken defaultToken1 = + persistResource( + new AllocationToken.Builder() + .setToken("aaaaa") + .setTokenType(DEFAULT_PROMO) + .setDiscountFraction(0.5) + .setDiscountYears(1) + .setAllowedTlds(ImmutableSet.of("tld")) + .build()); + persistResource( + Tld.get("tld") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) + .build()); + runFlowAssertResponse( + loadFile( + "domain_renew_response_fee.xml", + ImmutableMap.of( + "NAME", + "example.tld", + "PERIOD", + "5", + "EX_DATE", + "2005-04-03T22:00:00.0Z", + "FEE", + "49.50", + "CURRENCY", + "USD", + "FEE_VERSION", + "fee-0.6", + "FEE_NS", + "fee"))); + } + + @Test + void testFailure_wrongFeeAmountTooLow_defaultToken_v06() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_06_MAP); + persistDomain(); + AllocationToken defaultToken1 = + persistResource( + new AllocationToken.Builder() + .setToken("aaaaa") + .setTokenType(DEFAULT_PROMO) + .setDiscountFraction(0.5) + .setDiscountYears(1) + .setAllowedTlds(ImmutableSet.of("tld")) + .build()); + persistResource( + Tld.get("tld") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_wrongFeeAmountTooHigh_defaultToken_v11() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_11_MAP); + persistDomain(); + AllocationToken defaultToken1 = + persistResource( + new AllocationToken.Builder() + .setToken("aaaaa") + .setTokenType(DEFAULT_PROMO) + .setDiscountFraction(0.5) + .setDiscountYears(1) + .setAllowedTlds(ImmutableSet.of("tld")) + .build()); + persistResource( + Tld.get("tld") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) + .build()); + runFlowAssertResponse( + loadFile( + "domain_renew_response_fee.xml", + ImmutableMap.of( + "NAME", + "example.tld", + "PERIOD", + "5", + "EX_DATE", + "2005-04-03T22:00:00.0Z", + "FEE", + "49.50", + "CURRENCY", + "USD", + "FEE_VERSION", + "fee-0.11", + "FEE_NS", + "fee"))); + } + + @Test + void testFailure_wrongFeeAmountTooLow_defaultToken_v11() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_11_MAP); + persistDomain(); + AllocationToken defaultToken1 = + persistResource( + new AllocationToken.Builder() + .setToken("aaaaa") + .setTokenType(DEFAULT_PROMO) + .setDiscountFraction(0.5) + .setDiscountYears(1) + .setAllowedTlds(ImmutableSet.of("tld")) + .build()); + persistResource( + Tld.get("tld") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_wrongFeeAmountTooHigh_defaultToken_v12() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_12_MAP); + persistDomain(); + AllocationToken defaultToken1 = + persistResource( + new AllocationToken.Builder() + .setToken("aaaaa") + .setTokenType(DEFAULT_PROMO) + .setDiscountFraction(0.5) + .setDiscountYears(1) + .setAllowedTlds(ImmutableSet.of("tld")) + .build()); + persistResource( + Tld.get("tld") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) + .build()); + runFlowAssertResponse( + loadFile( + "domain_renew_response_fee.xml", + ImmutableMap.of( + "NAME", + "example.tld", + "PERIOD", + "5", + "EX_DATE", + "2005-04-03T22:00:00.0Z", + "FEE", + "49.50", + "CURRENCY", + "USD", + "FEE_VERSION", + "fee-0.12", + "FEE_NS", + "fee"))); + } + + @Test + void testFailure_wrongFeeAmountTooLow_defaultToken_v12() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_06_MAP); + persistDomain(); + AllocationToken defaultToken1 = + persistResource( + new AllocationToken.Builder() + .setToken("aaaaa") + .setTokenType(DEFAULT_PROMO) + .setDiscountFraction(0.5) + .setDiscountYears(1) + .setAllowedTlds(ImmutableSet.of("tld")) + .build()); + persistResource( + Tld.get("tld") + .asBuilder() + .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v06() throws Exception { + setEppInput("domain_renew_fee_refundable.xml", FEE_06_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v11() throws Exception { + setEppInput("domain_renew_fee_refundable.xml", FEE_11_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v12() throws Exception { + setEppInput("domain_renew_fee_refundable.xml", FEE_12_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v06() throws Exception { + setEppInput("domain_renew_fee_grace_period.xml", FEE_06_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v11() throws Exception { + setEppInput("domain_renew_fee_grace_period.xml", FEE_11_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v12() throws Exception { + setEppInput("domain_renew_fee_grace_period.xml", FEE_12_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v06() throws Exception { + setEppInput("domain_renew_fee_applied.xml", FEE_06_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v11() throws Exception { + setEppInput("domain_renew_fee_applied.xml", FEE_11_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v12() throws Exception { + setEppInput("domain_renew_fee_applied.xml", FEE_12_MAP); + persistDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_fee_v06() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_06_MAP); + persistDomain(); + doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_06_MAP); + } + + @Test + void testSuccess_fee_v11() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_11_MAP); + persistDomain(); + doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_11_MAP); + } + + @Test + void testSuccess_fee_v12() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_12_MAP); + persistDomain(); + doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_12_MAP); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v06() throws Exception { + setEppInput("domain_renew_fee_defaults.xml", FEE_06_MAP); + persistDomain(); + doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_06_MAP); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v11() throws Exception { + setEppInput("domain_renew_fee_defaults.xml", FEE_11_MAP); + persistDomain(); + doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_11_MAP); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v12() throws Exception { + setEppInput("domain_renew_fee_defaults.xml", FEE_12_MAP); + persistDomain(); + doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_12_MAP); + } + + @Test + void testSuccess_anchorTenant_premiumDomain_v06() throws Exception { + persistResource( + Tld.get("tld") + .asBuilder() + .setPremiumList(persistPremiumList("tld", USD, "example,USD 100")) + .build()); + persistDomain(NONPREMIUM, null); + setRegistrarIdForFlow("NewRegistrar"); + ImmutableMap customFeeMap = updateSubstitutions(FEE_06_MAP, "FEE", "55.00"); + setEppInput("domain_renew_fee.xml", customFeeMap); + doSuccessfulTest( + "domain_renew_response_fee.xml", + 5, + "NewRegistrar", + UserPrivileges.SUPERUSER, + customFeeMap, + Money.of(USD, 55), + NONPREMIUM, + null); + } + + @Test + void testSuccess_customLogicFee_v06() throws Exception { + // The "costly-renew" domain has an additional RENEW fee of 100 from custom logic on top of the + // normal $11 standard renew price for this TLD. + ImmutableMap customFeeMap = + updateSubstitutions( + FEE_06_MAP, + "NAME", + "costly-renew.tld", + "PERIOD", + "1", + "EX_DATE", + "2001-04-03T22:00:00.0Z", + "FEE", + "111.00"); + setEppInput("domain_renew_fee.xml", customFeeMap); + persistDomain(); + doSuccessfulTest( + "domain_renew_response_fee.xml", + 1, + "TheRegistrar", + UserPrivileges.NORMAL, + customFeeMap, + Money.of(USD, 111)); + } + + private void doSuccessfulTest(String responseFilename, int renewalYears) throws Exception { + doSuccessfulTest(responseFilename, renewalYears, ImmutableMap.of()); + } + + private void doSuccessfulTest( + String responseFilename, int renewalYears, Map substitutions) + throws Exception { + doSuccessfulTest( + responseFilename, + renewalYears, + "TheRegistrar", + UserPrivileges.NORMAL, + substitutions, + Money.of(USD, 11).multipliedBy(renewalYears), + DEFAULT, + null); + } + + private void doSuccessfulTest( + String responseFilename, + int renewalYears, + String renewalClientId, + UserPrivileges userPrivileges, + Map substitutions, + Money totalRenewCost) + throws Exception { + doSuccessfulTest( + responseFilename, + renewalYears, + renewalClientId, + userPrivileges, + substitutions, + totalRenewCost, + DEFAULT, + null); + } + + private void doSuccessfulTest( + String responseFilename, + int renewalYears, + String renewalClientId, + UserPrivileges userPrivileges, + Map substitutions, + Money totalRenewCost, + RenewalPriceBehavior renewalPriceBehavior, + @Nullable Money renewalPrice) + throws Exception { + assertMutatingFlow(true); + DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime(); + DateTime newExpiration = currentExpiration.plusYears(renewalYears); + runFlowAssertResponse( + CommitMode.LIVE, userPrivileges, loadFile(responseFilename, substitutions)); + Domain domain = reloadResourceByForeignKey(); + assertLastHistoryContainsResource(domain); + DomainHistory historyEntryDomainRenew = + getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_RENEW, DomainHistory.class); + assertThat(loadByKey(domain.getAutorenewBillingEvent()).getEventTime()) + .isEqualTo(newExpiration); + assertAboutDomains() + .that(domain) + .isActiveAt(clock.nowUtc()) + .and() + .hasRegistrationExpirationTime(newExpiration) + .and() + .hasOneHistoryEntryEachOfTypes( + HistoryEntry.Type.DOMAIN_CREATE, HistoryEntry.Type.DOMAIN_RENEW) + .and() + .hasLastEppUpdateTime(clock.nowUtc()) + .and() + .hasLastEppUpdateRegistrarId(renewalClientId); + assertAboutHistoryEntries().that(historyEntryDomainRenew).hasPeriodYears(renewalYears); + BillingEvent renewBillingEvent = + new BillingEvent.Builder() + .setReason(Reason.RENEW) + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId(renewalClientId) + .setCost(totalRenewCost) + .setPeriodYears(renewalYears) + .setEventTime(clock.nowUtc()) + .setBillingTime(clock.nowUtc().plus(Tld.get("tld").getRenewGracePeriodLength())) + .setDomainHistory(historyEntryDomainRenew) + .build(); + assertBillingEvents( + renewBillingEvent, + new BillingRecurrence.Builder() + .setReason(Reason.RENEW) + .setRenewalPriceBehavior(renewalPriceBehavior) + .setRenewalPrice(renewalPrice) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId("TheRegistrar") + .setEventTime(expirationTime) + .setRecurrenceEndTime(clock.nowUtc()) + .setDomainHistory( + getOnlyHistoryEntryOfType( + domain, HistoryEntry.Type.DOMAIN_CREATE, DomainHistory.class)) + .build(), + new BillingRecurrence.Builder() + .setReason(Reason.RENEW) + .setRenewalPriceBehavior(renewalPriceBehavior) + .setRenewalPrice(renewalPrice) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId("TheRegistrar") + .setEventTime(domain.getRegistrationExpirationTime()) + .setRecurrenceEndTime(END_OF_TIME) + .setDomainHistory(historyEntryDomainRenew) + .build()); + // There should only be the new autorenew poll message, as the old one will have been deleted + // since it had no messages left to deliver. + assertPollMessages( + new PollMessage.Autorenew.Builder() + .setTargetId(getUniqueIdFromCommand()) + .setRegistrarId("TheRegistrar") + .setEventTime(domain.getRegistrationExpirationTime()) + .setAutorenewEndTime(END_OF_TIME) + .setMsg("Domain was auto-renewed.") + .setHistoryEntry(historyEntryDomainRenew) + .build()); + assertGracePeriods( + domain.getGracePeriods(), + ImmutableMap.of( + GracePeriod.create( + GracePeriodStatus.RENEW, + domain.getRepoId(), + clock.nowUtc().plus(Tld.get("tld").getRenewGracePeriodLength()), + renewalClientId, + null), + renewBillingEvent)); + } +} diff --git a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java index ea28afc05..6e1e4dbe4 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java @@ -119,12 +119,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase "FEE", "55.00", "CURRENCY", "USD"); - private static final ImmutableMap FEE_06_MAP = - updateSubstitutions(FEE_BASE_MAP, "FEE_VERSION", "0.6", "FEE_NS", "fee"); - private static final ImmutableMap FEE_11_MAP = - updateSubstitutions(FEE_BASE_MAP, "FEE_VERSION", "0.11", "FEE_NS", "fee11"); - private static final ImmutableMap FEE_12_MAP = - updateSubstitutions(FEE_BASE_MAP, "FEE_VERSION", "0.12", "FEE_NS", "fee12"); + private static final ImmutableMap FEE_STD_1_0_MAP = + updateSubstitutions(FEE_BASE_MAP, "FEE_VERSION", "epp:fee-1.0", "FEE_NS", "fee1_00"); private final DateTime expirationTime = DateTime.parse("2000-04-03T22:00:00.0Z"); @@ -390,7 +386,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testSuccess_internalRegiration_premiumDomain() throws Exception { + void testSuccess_internalRegiration_premiumDomain_std_v1() throws Exception { persistResource( Tld.get("tld") .asBuilder() @@ -398,7 +394,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase .build()); persistDomain(SPECIFIED, Money.of(USD, 2)); setRegistrarIdForFlow("NewRegistrar"); - ImmutableMap customFeeMap = updateSubstitutions(FEE_06_MAP, "FEE", "10.00"); + ImmutableMap customFeeMap = + updateSubstitutions(FEE_STD_1_0_MAP, "FEE", "10.00"); setEppInput("domain_renew_fee.xml", customFeeMap); doSuccessfulTest( "domain_renew_response_fee.xml", @@ -427,7 +424,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testSuccess_anchorTenant_premiumDomain() throws Exception { + void testSuccess_anchorTenant_premiumDomain_std_v1() throws Exception { persistResource( Tld.get("tld") .asBuilder() @@ -435,7 +432,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase .build()); persistDomain(NONPREMIUM, null); setRegistrarIdForFlow("NewRegistrar"); - ImmutableMap customFeeMap = updateSubstitutions(FEE_06_MAP, "FEE", "55.00"); + ImmutableMap customFeeMap = + updateSubstitutions(FEE_STD_1_0_MAP, "FEE", "55.00"); setEppInput("domain_renew_fee.xml", customFeeMap); doSuccessfulTest( "domain_renew_response_fee.xml", @@ -449,12 +447,12 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testSuccess_customLogicFee() throws Exception { + void testSuccess_customLogicFee_std_v1() throws Exception { // The "costly-renew" domain has an additional RENEW fee of 100 from custom logic on top of the // normal $11 standard renew price for this TLD. ImmutableMap customFeeMap = updateSubstitutions( - FEE_06_MAP, + FEE_STD_1_0_MAP, "NAME", "costly-renew.tld", "PERIOD", @@ -475,121 +473,45 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testSuccess_fee_v06() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_06_MAP); + void testSuccess_fee_std_v1() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_STD_1_0_MAP); persistDomain(); - doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_06_MAP); + doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_STD_1_0_MAP); } @Test - void testSuccess_fee_v11() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_11_MAP); + void testSuccess_fee_withDefaultAttributes_std_v1() throws Exception { + setEppInput("domain_renew_fee_defaults.xml", FEE_STD_1_0_MAP); persistDomain(); - doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_11_MAP); - } - - @Test - void testSuccess_fee_v12() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_12_MAP); - persistDomain(); - doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_12_MAP); - } - - @Test - void testSuccess_fee_withDefaultAttributes_v06() throws Exception { - setEppInput("domain_renew_fee_defaults.xml", FEE_06_MAP); - persistDomain(); - doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_06_MAP); - } - - @Test - void testSuccess_fee_withDefaultAttributes_v11() throws Exception { - setEppInput("domain_renew_fee_defaults.xml", FEE_11_MAP); - persistDomain(); - doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_11_MAP); - } - - @Test - void testSuccess_fee_withDefaultAttributes_v12() throws Exception { - setEppInput("domain_renew_fee_defaults.xml", FEE_12_MAP); - persistDomain(); - doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_12_MAP); + doSuccessfulTest("domain_renew_response_fee.xml", 5, FEE_STD_1_0_MAP); } @Test void testFailure_fee_unknownCurrency() { - setEppInput("domain_renew_fee.xml", updateSubstitutions(FEE_06_MAP, "CURRENCY", "BAD")); + setEppInput("domain_renew_fee.xml", updateSubstitutions(FEE_STD_1_0_MAP, "CURRENCY", "BAD")); EppException thrown = assertThrows(UnknownCurrencyEppException.class, this::persistDomain); assertAboutEppExceptions().that(thrown).marshalsToXml(); } @Test - void testFailure_refundableFee_v06() throws Exception { - setEppInput("domain_renew_fee_refundable.xml", FEE_06_MAP); + void testFailure_refundableFee_std_v1() throws Exception { + setEppInput("domain_renew_fee_refundable.xml", FEE_STD_1_0_MAP); persistDomain(); EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); assertAboutEppExceptions().that(thrown).marshalsToXml(); } @Test - void testFailure_refundableFee_v11() throws Exception { - setEppInput("domain_renew_fee_refundable.xml", FEE_11_MAP); + void testFailure_gracePeriodFee_std_v1() throws Exception { + setEppInput("domain_renew_fee_grace_period.xml", FEE_STD_1_0_MAP); persistDomain(); EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); assertAboutEppExceptions().that(thrown).marshalsToXml(); } @Test - void testFailure_refundableFee_v12() throws Exception { - setEppInput("domain_renew_fee_refundable.xml", FEE_12_MAP); - persistDomain(); - EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_gracePeriodFee_v06() throws Exception { - setEppInput("domain_renew_fee_grace_period.xml", FEE_06_MAP); - persistDomain(); - EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_gracePeriodFee_v11() throws Exception { - setEppInput("domain_renew_fee_grace_period.xml", FEE_11_MAP); - persistDomain(); - EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_gracePeriodFee_v12() throws Exception { - setEppInput("domain_renew_fee_grace_period.xml", FEE_12_MAP); - persistDomain(); - EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_appliedFee_v06() throws Exception { - setEppInput("domain_renew_fee_applied.xml", FEE_06_MAP); - persistDomain(); - EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_appliedFee_v11() throws Exception { - setEppInput("domain_renew_fee_applied.xml", FEE_11_MAP); - persistDomain(); - EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_appliedFee_v12() throws Exception { - setEppInput("domain_renew_fee_applied.xml", FEE_12_MAP); + void testFailure_appliedFee_std_v1() throws Exception { + setEppInput("domain_renew_fee_applied.xml", FEE_STD_1_0_MAP); persistDomain(); EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); assertAboutEppExceptions().that(thrown).marshalsToXml(); @@ -991,8 +913,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testFailure_wrongFeeAmount_v06() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_06_MAP); + void testFailure_wrongFeeAmount_std_v1() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_STD_1_0_MAP); persistResource( Tld.get("tld") .asBuilder() @@ -1004,34 +926,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testFailure_wrongFeeAmount_v11() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_11_MAP); - persistResource( - Tld.get("tld") - .asBuilder() - .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) - .build()); - persistDomain(); - EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_wrongFeeAmount_v12() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_12_MAP); - persistResource( - Tld.get("tld") - .asBuilder() - .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) - .build()); - persistDomain(); - EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_wrongCurrency_v06() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_06_MAP); + void testFailure_wrongCurrency_std_v1() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_STD_1_0_MAP); persistResource( Tld.get("tld") .asBuilder() @@ -1050,64 +946,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testFailure_wrongCurrency_v11() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_11_MAP); - persistResource( - Tld.get("tld") - .asBuilder() - .setCurrency(EUR) - .setCreateBillingCostTransitions( - ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 13))) - .setRestoreBillingCost(Money.of(EUR, 11)) - .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 7))) - .setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(EUR))) - .setRegistryLockOrUnlockBillingCost(Money.of(EUR, 20)) - .setServerStatusChangeBillingCost(Money.of(EUR, 19)) - .build()); - persistDomain(); - EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_wrongCurrency_v12() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_12_MAP); - persistResource( - Tld.get("tld") - .asBuilder() - .setCurrency(EUR) - .setCreateBillingCostTransitions( - ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 13))) - .setRestoreBillingCost(Money.of(EUR, 11)) - .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 7))) - .setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(EUR))) - .setRegistryLockOrUnlockBillingCost(Money.of(EUR, 20)) - .setServerStatusChangeBillingCost(Money.of(EUR, 19)) - .build()); - persistDomain(); - EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_feeGivenInWrongScale_v06() throws Exception { - setEppInput("domain_renew_fee_bad_scale.xml", FEE_06_MAP); - persistDomain(); - EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_feeGivenInWrongScale_v11() throws Exception { - setEppInput("domain_renew_fee_bad_scale.xml", FEE_11_MAP); - persistDomain(); - EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_feeGivenInWrongScale_v12() throws Exception { - setEppInput("domain_renew_fee_bad_scale.xml", FEE_12_MAP); + void testFailure_feeGivenInWrongScale_std_v1() throws Exception { + setEppInput("domain_renew_fee_bad_scale.xml", FEE_STD_1_0_MAP); persistDomain(); EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); assertAboutEppExceptions().that(thrown).marshalsToXml(); @@ -1522,8 +1362,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testSuccess_doesNotApplyNonPremiumDefaultTokenToPremiumName() throws Exception { - ImmutableMap customFeeMap = updateSubstitutions(FEE_06_MAP, "FEE", "500"); + void testSuccess_doesNotApplyNonPremiumDefaultTokenToPremiumName_std_v1() throws Exception { + ImmutableMap customFeeMap = updateSubstitutions(FEE_STD_1_0_MAP, "FEE", "500"); setEppInput("domain_renew_fee.xml", customFeeMap); persistDomain(); AllocationToken defaultToken1 = @@ -1556,9 +1396,9 @@ class DomainRenewFlowTest extends ResourceFlowTestCase "CURRENCY", "USD", "FEE_VERSION", - "0.6", + "epp:fee-1.0", "FEE_NS", - "fee"))); + "fee1_00"))); BillingEvent billingEvent = Iterables.getOnlyElement(DatabaseHelper.loadAllOf(BillingEvent.class)); assertThat(billingEvent.getTargetId()).isEqualTo("example.tld"); @@ -1662,8 +1502,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase } @Test - void testSuccess_wrongFeeAmountTooHigh_defaultToken_v06() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_06_MAP); + void testSuccess_wrongFeeAmountTooHigh_defaultToken_std_v1() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_STD_1_0_MAP); persistDomain(); AllocationToken defaultToken1 = persistResource( @@ -1694,136 +1534,14 @@ class DomainRenewFlowTest extends ResourceFlowTestCase "CURRENCY", "USD", "FEE_VERSION", - "0.6", + "epp:fee-1.0", "FEE_NS", - "fee"))); + "fee1_00"))); } @Test - void testFailure_wrongFeeAmountTooLow_defaultToken_v06() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_06_MAP); - persistDomain(); - AllocationToken defaultToken1 = - persistResource( - new AllocationToken.Builder() - .setToken("aaaaa") - .setTokenType(DEFAULT_PROMO) - .setDiscountFraction(0.5) - .setDiscountYears(1) - .setAllowedTlds(ImmutableSet.of("tld")) - .build()); - persistResource( - Tld.get("tld") - .asBuilder() - .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) - .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) - .build()); - EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testSuccess_wrongFeeAmountTooHigh_defaultToken_v11() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_11_MAP); - persistDomain(); - AllocationToken defaultToken1 = - persistResource( - new AllocationToken.Builder() - .setToken("aaaaa") - .setTokenType(DEFAULT_PROMO) - .setDiscountFraction(0.5) - .setDiscountYears(1) - .setAllowedTlds(ImmutableSet.of("tld")) - .build()); - persistResource( - Tld.get("tld") - .asBuilder() - .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) - .build()); - runFlowAssertResponse( - loadFile( - "domain_renew_response_fee.xml", - ImmutableMap.of( - "NAME", - "example.tld", - "PERIOD", - "5", - "EX_DATE", - "2005-04-03T22:00:00.0Z", - "FEE", - "49.50", - "CURRENCY", - "USD", - "FEE_VERSION", - "0.11", - "FEE_NS", - "fee"))); - } - - @Test - void testFailure_wrongFeeAmountTooLow_defaultToken_v11() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_11_MAP); - persistDomain(); - AllocationToken defaultToken1 = - persistResource( - new AllocationToken.Builder() - .setToken("aaaaa") - .setTokenType(DEFAULT_PROMO) - .setDiscountFraction(0.5) - .setDiscountYears(1) - .setAllowedTlds(ImmutableSet.of("tld")) - .build()); - persistResource( - Tld.get("tld") - .asBuilder() - .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) - .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) - .build()); - EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testSuccess_wrongFeeAmountTooHigh_defaultToken_v12() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_12_MAP); - persistDomain(); - AllocationToken defaultToken1 = - persistResource( - new AllocationToken.Builder() - .setToken("aaaaa") - .setTokenType(DEFAULT_PROMO) - .setDiscountFraction(0.5) - .setDiscountYears(1) - .setAllowedTlds(ImmutableSet.of("tld")) - .build()); - persistResource( - Tld.get("tld") - .asBuilder() - .setDefaultPromoTokens(ImmutableList.of(defaultToken1.createVKey())) - .build()); - runFlowAssertResponse( - loadFile( - "domain_renew_response_fee.xml", - ImmutableMap.of( - "NAME", - "example.tld", - "PERIOD", - "5", - "EX_DATE", - "2005-04-03T22:00:00.0Z", - "FEE", - "49.50", - "CURRENCY", - "USD", - "FEE_VERSION", - "0.12", - "FEE_NS", - "fee"))); - } - - @Test - void testFailure_wrongFeeAmountTooLow_defaultToken_v12() throws Exception { - setEppInput("domain_renew_fee.xml", FEE_06_MAP); + void testFailure_wrongFeeAmountTooLow_defaultToken_std_v1() throws Exception { + setEppInput("domain_renew_fee.xml", FEE_STD_1_0_MAP); persistDomain(); AllocationToken defaultToken1 = persistResource( diff --git a/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowOldFeeExtensionsTest.java b/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowOldFeeExtensionsTest.java new file mode 100644 index 000000000..970067721 --- /dev/null +++ b/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowOldFeeExtensionsTest.java @@ -0,0 +1,351 @@ +// Copyright 2026 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.flows.domain; + +import static google.registry.testing.DatabaseHelper.createTld; +import static google.registry.testing.DatabaseHelper.loadRegistrar; +import static google.registry.testing.DatabaseHelper.persistResource; +import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; +import static google.registry.util.DateTimeUtils.START_OF_TIME; +import static org.joda.money.CurrencyUnit.EUR; +import static org.joda.money.CurrencyUnit.USD; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedMap; +import google.registry.flows.EppException; +import google.registry.flows.FlowUtils.UnknownCurrencyEppException; +import google.registry.flows.domain.DomainFlowUtils.CurrencyUnitMismatchException; +import google.registry.flows.domain.DomainFlowUtils.CurrencyValueScaleException; +import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException; +import google.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException; +import google.registry.flows.domain.DomainFlowUtils.UnsupportedFeeAttributeException; +import google.registry.model.domain.Domain; +import google.registry.model.domain.DomainHistory; +import google.registry.model.domain.GracePeriod; +import google.registry.model.domain.rgp.GracePeriodStatus; +import google.registry.model.eppcommon.StatusValue; +import google.registry.model.poll.PollMessage; +import google.registry.model.reporting.HistoryEntry; +import google.registry.model.tld.Tld; +import google.registry.testing.DatabaseHelper; +import java.util.Map; +import org.joda.money.Money; +import org.joda.time.DateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Tests for {@link DomainRestoreRequestFlow} that use the old fee extensions (0.6, 0.11, 0.12). */ +public class DomainRestoreRequestFlowOldFeeExtensionsTest + extends ProductionSimulatingFeeExtensionsTest { + + private static final ImmutableMap FEE_06_MAP = + ImmutableMap.of("FEE_VERSION", "fee-0.6", "FEE_NS", "fee", "CURRENCY", "USD"); + private static final ImmutableMap FEE_11_MAP = + ImmutableMap.of("FEE_VERSION", "fee-0.11", "FEE_NS", "fee11", "CURRENCY", "USD"); + private static final ImmutableMap FEE_12_MAP = + ImmutableMap.of("FEE_VERSION", "fee-0.12", "FEE_NS", "fee12", "CURRENCY", "USD"); + + @BeforeEach + void beforeEachDomainRestoreRequestFlowOldFeeExtensionsTest() { + createTld("tld"); + persistResource( + loadRegistrar("TheRegistrar") + .asBuilder() + .setBillingAccountMap(ImmutableMap.of(USD, "123", EUR, "567")) + .build()); + setEppInput("domain_update_restore_request.xml", ImmutableMap.of("DOMAIN", "example.tld")); + } + + @Test + void testFailure_wrongFeeAmount_v06() throws Exception { + setEppInput("domain_update_restore_request_fee.xml", FEE_06_MAP); + persistPendingDeleteDomain(); + persistResource(Tld.get("tld").asBuilder().setRestoreBillingCost(Money.of(USD, 100)).build()); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmount_v11() throws Exception { + setEppInput("domain_update_restore_request_fee.xml", FEE_11_MAP); + persistPendingDeleteDomain(); + persistResource(Tld.get("tld").asBuilder().setRestoreBillingCost(Money.of(USD, 100)).build()); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongFeeAmount_v12() throws Exception { + setEppInput("domain_update_restore_request_fee.xml", FEE_12_MAP); + persistPendingDeleteDomain(); + persistResource(Tld.get("tld").asBuilder().setRestoreBillingCost(Money.of(USD, 100)).build()); + EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v06() throws Exception { + setEppInput("domain_update_restore_request_fee_bad_scale.xml", FEE_06_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v11() throws Exception { + setEppInput("domain_update_restore_request_fee_bad_scale.xml", FEE_11_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v12() throws Exception { + setEppInput("domain_update_restore_request_fee_bad_scale.xml", FEE_12_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(CurrencyValueScaleException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v06() throws Exception { + setEppInput("domain_update_restore_request_fee_applied.xml", FEE_06_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v11() throws Exception { + setEppInput("domain_update_restore_request_fee_applied.xml", FEE_11_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v12() throws Exception { + setEppInput("domain_update_restore_request_fee_applied.xml", FEE_12_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v06() throws Exception { + setEppInput("domain_update_restore_request_fee_defaults.xml", FEE_06_MAP); + persistPendingDeleteDomain(); + runFlowAssertResponse(loadFile("domain_update_restore_request_response_fee.xml", FEE_06_MAP)); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v11() throws Exception { + setEppInput("domain_update_restore_request_fee_defaults.xml", FEE_11_MAP); + persistPendingDeleteDomain(); + runFlowAssertResponse(loadFile("domain_update_restore_request_response_fee.xml", FEE_11_MAP)); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v12() throws Exception { + setEppInput("domain_update_restore_request_fee_defaults.xml", FEE_12_MAP); + persistPendingDeleteDomain(); + runFlowAssertResponse(loadFile("domain_update_restore_request_response_fee.xml", FEE_12_MAP)); + } + + @Test + void testSuccess_fee_v06() throws Exception { + setEppInput("domain_update_restore_request_fee.xml", FEE_06_MAP); + persistPendingDeleteDomain(); + runFlowAssertResponse(loadFile("domain_update_restore_request_response_fee.xml", FEE_06_MAP)); + } + + @Test + void testSuccess_fee_v06_noRenewal() throws Exception { + setEppInput("domain_update_restore_request_fee_no_renewal.xml", FEE_06_MAP); + persistPendingDeleteDomain(clock.nowUtc().plusMonths(6)); + runFlowAssertResponse( + loadFile("domain_update_restore_request_response_fee_no_renewal.xml", FEE_06_MAP)); + } + + @Test + void testSuccess_fee_v11() throws Exception { + setEppInput("domain_update_restore_request_fee.xml", FEE_11_MAP); + persistPendingDeleteDomain(); + runFlowAssertResponse(loadFile("domain_update_restore_request_response_fee.xml", FEE_11_MAP)); + } + + @Test + void testSuccess_fee_v12() throws Exception { + setEppInput("domain_update_restore_request_fee.xml", FEE_12_MAP); + persistPendingDeleteDomain(); + runFlowAssertResponse(loadFile("domain_update_restore_request_response_fee.xml", FEE_12_MAP)); + } + + @Test + void testFailure_refundableFee_v06() throws Exception { + setEppInput("domain_update_restore_request_fee_refundable.xml", FEE_06_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v11() throws Exception { + setEppInput("domain_update_restore_request_fee_refundable.xml", FEE_11_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v12() throws Exception { + setEppInput("domain_update_restore_request_fee_refundable.xml", FEE_12_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v06() throws Exception { + setEppInput("domain_update_restore_request_fee_grace_period.xml", FEE_06_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v11() throws Exception { + setEppInput("domain_update_restore_request_fee_grace_period.xml", FEE_11_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v12() throws Exception { + setEppInput("domain_update_restore_request_fee_grace_period.xml", FEE_12_MAP); + persistPendingDeleteDomain(); + EppException thrown = assertThrows(UnsupportedFeeAttributeException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + private void runWrongCurrencyTest(Map substitutions) throws Exception { + setEppInput("domain_update_restore_request_fee.xml", substitutions); + persistPendingDeleteDomain(); + persistResource( + Tld.get("tld") + .asBuilder() + .setCurrency(EUR) + .setCreateBillingCostTransitions( + ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 13))) + .setRestoreBillingCost(Money.of(EUR, 11)) + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(EUR, 7))) + .setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.zero(EUR))) + .setServerStatusChangeBillingCost(Money.of(EUR, 19)) + .setRegistryLockOrUnlockBillingCost(Money.of(EUR, 0)) + .build()); + EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongCurrency_v06() throws Exception { + runWrongCurrencyTest(FEE_06_MAP); + } + + @Test + void testFailure_wrongCurrency_v11() throws Exception { + runWrongCurrencyTest(FEE_11_MAP); + } + + @Test + void testFailure_wrongCurrency_v12() throws Exception { + runWrongCurrencyTest(FEE_12_MAP); + } + + @Test + void testFailure_premiumBlocked_v12() throws Exception { + createTld("example"); + setEppInput("domain_update_restore_request_premium.xml", FEE_12_MAP); + persistPendingDeleteDomain(); + // Modify the Registrar to block premium names. + persistResource(loadRegistrar("TheRegistrar").asBuilder().setBlockPremiumNames(true).build()); + EppException thrown = assertThrows(PremiumNameBlockedException.class, this::runFlow); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_premiumNotBlocked_andNoRenewal_v12() throws Exception { + createTld("example"); + setEppInput("domain_update_restore_request_premium_no_renewal.xml", FEE_12_MAP); + persistPendingDeleteDomain(clock.nowUtc().plusYears(2)); + runFlowAssertResponse( + loadFile("domain_update_restore_request_response_fee_no_renewal.xml", FEE_12_MAP)); + } + + @Test + void testFailure_fee_unknownCurrency_v12() { + ImmutableMap substitutions = + ImmutableMap.of("FEE_VERSION", "fee-0.12", "FEE_NS", "fee12", "CURRENCY", "BAD"); + setEppInput("domain_update_restore_request_fee.xml", substitutions); + EppException thrown = + assertThrows(UnknownCurrencyEppException.class, this::persistPendingDeleteDomain); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + private Domain persistPendingDeleteDomain() throws Exception { + // The domain is now past what had been its expiration date at the time of deletion. + return persistPendingDeleteDomain(clock.nowUtc().minusDays(5)); + } + + private Domain persistPendingDeleteDomain(DateTime expirationTime) throws Exception { + Domain domain = persistResource(DatabaseHelper.newDomain(getUniqueIdFromCommand())); + HistoryEntry historyEntry = + persistResource( + new DomainHistory.Builder() + .setType(HistoryEntry.Type.DOMAIN_DELETE) + .setModificationTime(clock.nowUtc()) + .setRegistrarId(domain.getCurrentSponsorRegistrarId()) + .setDomain(domain) + .build()); + domain = + persistResource( + domain + .asBuilder() + .setRegistrationExpirationTime(expirationTime) + .setDeletionTime(clock.nowUtc().plusDays(35)) + .addGracePeriod( + GracePeriod.create( + GracePeriodStatus.REDEMPTION, + domain.getRepoId(), + clock.nowUtc().plusDays(1), + "TheRegistrar", + null)) + .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) + .setDeletePollMessage( + persistResource( + new PollMessage.OneTime.Builder() + .setRegistrarId("TheRegistrar") + .setEventTime(clock.nowUtc().plusDays(5)) + .setHistoryEntry(historyEntry) + .build()) + .createVKey()) + .build()); + clock.advanceOneMilli(); + return domain; + } +} diff --git a/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java index 1dceced56..8ba178d3d 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java @@ -86,12 +86,8 @@ import org.junit.jupiter.api.Test; /** Unit tests for {@link DomainRestoreRequestFlow}. */ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase { - private static final ImmutableMap FEE_06_MAP = - ImmutableMap.of("FEE_VERSION", "0.6", "FEE_NS", "fee", "CURRENCY", "USD"); - private static final ImmutableMap FEE_11_MAP = - ImmutableMap.of("FEE_VERSION", "0.11", "FEE_NS", "fee11", "CURRENCY", "USD"); - private static final ImmutableMap FEE_12_MAP = - ImmutableMap.of("FEE_VERSION", "0.12", "FEE_NS", "fee12", "CURRENCY", "USD"); + private static final ImmutableMap FEE_STD_1_0_MAP = + ImmutableMap.of("FEE_VERSION", "epp:fee-1.0", "FEE_NS", "fee1_00", "CURRENCY", "USD"); @BeforeEach void initDomainTest() { @@ -308,7 +304,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase substitutions = - ImmutableMap.of("FEE_VERSION", "0.12", "FEE_NS", "fee12", "CURRENCY", "BAD"); + ImmutableMap.of("FEE_VERSION", "epp:fee-1.0", "FEE_NS", "fee1_00", "CURRENCY", "BAD"); setEppInput("domain_update_restore_request_fee.xml", substitutions); EppException thrown = assertThrows(UnknownCurrencyEppException.class, this::persistPendingDeleteDomain); @@ -381,72 +344,24 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase { + + private static final ImmutableMap BASE_FEE_MAP = + new ImmutableMap.Builder() + .put("DOMAIN", "example.tld") + .put("YEARS", "1") + .put("AMOUNT", "11.00") + .put("CURRENCY", "USD") + .build(); + private static final ImmutableMap FEE_06_MAP = + new ImmutableMap.Builder() + .putAll(BASE_FEE_MAP) + .put("FEE_VERSION", "fee-0.6") + .put("FEE_NS", "fee") + .build(); + private static final ImmutableMap FEE_11_MAP = + new ImmutableMap.Builder() + .putAll(BASE_FEE_MAP) + .put("FEE_VERSION", "fee-0.11") + .put("FEE_NS", "fee11") + .build(); + private static final ImmutableMap FEE_12_MAP = + new ImmutableMap.Builder() + .putAll(BASE_FEE_MAP) + .put("FEE_VERSION", "fee-0.12") + .put("FEE_NS", "fee12") + .build(); + private static final ImmutableMap RICH_DOMAIN_MAP = + ImmutableMap.builder() + .put("DOMAIN", "rich.example") + .put("YEARS", "1") + .put("AMOUNT", "100.00") + .put("CURRENCY", "USD") + .put("FEE_VERSION", "fee-0.12") + .put("FEE_NS", "fee12") + .build(); + + private static final DateTime TRANSFER_REQUEST_TIME = DateTime.parse("2000-06-06T22:00:00.0Z"); + private static final DateTime TRANSFER_EXPIRATION_TIME = + TRANSFER_REQUEST_TIME.plus(Tld.DEFAULT_AUTOMATIC_TRANSFER_LENGTH); + private static final Duration TIME_SINCE_REQUEST = Duration.standardDays(3); + private static final int EXTENDED_REGISTRATION_YEARS = 1; + private static final DateTime REGISTRATION_EXPIRATION_TIME = + DateTime.parse("2001-09-08T22:00:00.0Z"); + private static final DateTime EXTENDED_REGISTRATION_EXPIRATION_TIME = + REGISTRATION_EXPIRATION_TIME.plusYears(EXTENDED_REGISTRATION_YEARS); + + private Contact contact; + private Domain domain; + private Host subordinateHost; + private DomainHistory historyEntryDomainCreate; + + @BeforeEach + void beforeEachDomainTransferRequestFlowOldFeeExtensionsTest() { + setEppInput("domain_transfer_request.xml"); + setRegistrarIdForFlow("NewRegistrar"); + clock.setTo(TRANSFER_REQUEST_TIME.plus(TIME_SINCE_REQUEST)); + } + + @Test + void testFailure_wrongFeeAmount_v06() { + setupDomain("example", "tld"); + runWrongFeeAmountTest(FEE_06_MAP); + } + + @Test + void testFailure_wrongFeeAmount_v11() { + setupDomain("example", "tld"); + runWrongFeeAmountTest(FEE_11_MAP); + } + + @Test + void testFailure_wrongFeeAmount_v12() { + setupDomain("example", "tld"); + runWrongFeeAmountTest(FEE_12_MAP); + } + + @Test + void testFailure_appliedFee_v06() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_applied.xml", FEE_06_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v11() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_applied.xml", FEE_11_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_appliedFee_v12() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_applied.xml", FEE_12_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v06() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_grace_period.xml", FEE_06_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v11() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_grace_period.xml", FEE_11_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_gracePeriodFee_v12() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_grace_period.xml", FEE_12_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v06() throws Exception { + setupDomain("example", "tld"); + doSuccessfulTest( + "domain_transfer_request_fee_defaults.xml", + "domain_transfer_request_response_fee.xml", + FEE_06_MAP); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v11() throws Exception { + setupDomain("example", "tld"); + doSuccessfulTest( + "domain_transfer_request_fee_defaults.xml", + "domain_transfer_request_response_fee.xml", + FEE_11_MAP); + } + + @Test + void testSuccess_fee_withDefaultAttributes_v12() throws Exception { + setupDomain("example", "tld"); + doSuccessfulTest( + "domain_transfer_request_fee_defaults.xml", + "domain_transfer_request_response_fee.xml", + FEE_12_MAP); + } + + @Test + void testFailure_refundableFee_v06() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_refundable.xml", FEE_06_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v11() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_refundable.xml", FEE_11_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_refundableFee_v12() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + UnsupportedFeeAttributeException.class, + () -> doFailingTest("domain_transfer_request_fee_refundable.xml", FEE_12_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_wrongCurrency_v06() { + runWrongCurrencyTest(FEE_06_MAP); + } + + @Test + void testFailure_wrongCurrency_v11() { + runWrongCurrencyTest(FEE_11_MAP); + } + + @Test + void testFailure_wrongCurrency_v12() { + runWrongCurrencyTest(FEE_12_MAP); + } + + @Test + void testFailure_feeGivenInWrongScale_v06() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + CurrencyValueScaleException.class, + () -> doFailingTest("domain_transfer_request_fee_bad_scale.xml", FEE_06_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v11() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + CurrencyValueScaleException.class, + () -> doFailingTest("domain_transfer_request_fee_bad_scale.xml", FEE_11_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testFailure_feeGivenInWrongScale_v12() { + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + CurrencyValueScaleException.class, + () -> doFailingTest("domain_transfer_request_fee_bad_scale.xml", FEE_12_MAP)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + @Test + void testSuccess_fee_v06() throws Exception { + setupDomain("example", "tld"); + doSuccessfulTest( + "domain_transfer_request_fee.xml", "domain_transfer_request_response_fee.xml", FEE_06_MAP); + } + + @Test + void testSuccess_fee_v11() throws Exception { + setupDomain("example", "tld"); + doSuccessfulTest( + "domain_transfer_request_fee.xml", "domain_transfer_request_response_fee.xml", FEE_11_MAP); + } + + @Test + void testSuccess_fee_v12() throws Exception { + setupDomain("example", "tld"); + doSuccessfulTest( + "domain_transfer_request_fee.xml", "domain_transfer_request_response_fee.xml", FEE_12_MAP); + } + + @Test + void testSuccess_customLogicFee_v06() throws Exception { + setupDomain("expensive-domain", "foo"); + clock.advanceOneMilli(); + doSuccessfulTest( + "domain_transfer_request_separate_fees.xml", + "domain_transfer_request_response_fees.xml", + domain.getRegistrationExpirationTime().plusYears(1), + new ImmutableMap.Builder() + .put("DOMAIN", "expensive-domain.foo") + .put("YEARS", "1") + .put("AMOUNT", "111.00") + .put("EXDATE", "2002-09-08T22:00:00.0Z") + .put("FEE_VERSION", "fee-0.6") + .put("FEE_NS", "fee") + .build(), + Optional.of(Money.of(USD, 111))); + } + + @Test + void testSuccess_premiumNotBlocked_v12() throws Exception { + setupDomain("rich", "example"); + clock.advanceOneMilli(); + // We don't verify the results; just check that the flow doesn't fail. + runTest("domain_transfer_request_fee.xml", UserPrivileges.NORMAL, RICH_DOMAIN_MAP); + } + + @Test + void testFailure_superuserExtension_zeroPeriod_feeTransferExtension_v12() { + setupDomain("example", "tld"); + eppRequestSource = EppRequestSource.TOOL; + clock.advanceOneMilli(); + assertThrows( + TransferPeriodZeroAndFeeTransferExtensionException.class, + () -> + runTest( + "domain_transfer_request_fee_and_superuser_extension.xml", + UserPrivileges.SUPERUSER, + new ImmutableMap.Builder() + .putAll(FEE_12_MAP) + .put("PERIOD", "0") + .put("AUTOMATIC_TRANSFER_LENGTH", "5") + .build())); + } + + @Test + void testSuccess_premiumNotBlockedInSuperuserMode_v12() throws Exception { + setupDomain("rich", "example"); + clock.advanceOneMilli(); + // Modify the Registrar to block premium names. + persistResource(loadRegistrar("NewRegistrar").asBuilder().setBlockPremiumNames(true).build()); + // We don't verify the results; just check that the flow doesn't fail. + runTest("domain_transfer_request_fee.xml", UserPrivileges.SUPERUSER, RICH_DOMAIN_MAP); + } + + private void runWrongCurrencyTest(Map substitutions) { + Map fullSubstitutions = Maps.newHashMap(); + fullSubstitutions.putAll(substitutions); + fullSubstitutions.put("CURRENCY", "EUR"); + setupDomain("example", "tld"); + EppException thrown = + assertThrows( + CurrencyUnitMismatchException.class, + () -> doFailingTest("domain_transfer_request_fee.xml", fullSubstitutions)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + /** + * Runs a successful test. The extraExpectedBillingEvents parameter consists of cancellation + * billing event builders that have had all of their attributes set except for the parent history + * entry, which is filled in during the execution of this method. + */ + private void doSuccessfulTest( + String commandFilename, + String expectedXmlFilename, + DateTime expectedExpirationTime, + Map substitutions, + Optional transferCost, + BillingCancellation.Builder... extraExpectedBillingEvents) + throws Exception { + setEppInput(commandFilename, substitutions); + ImmutableSet originalGracePeriods = domain.getGracePeriods(); + // Replace the ROID in the xml file with the one generated in our test. + eppLoader.replaceAll("JD1234-REP", contact.getRepoId()); + // For all of the other transfer flow tests, 'now' corresponds to day 3 of the transfer, but + // for the request test we want that same 'now' to be the initial request time, so we shift + // the transfer timeline 3 days later by adjusting the implicit transfer time here. + Tld registry = Tld.get(domain.getTld()); + DateTime implicitTransferTime = clock.nowUtc().plus(registry.getAutomaticTransferLength()); + // Setup done; run the test. + assertMutatingFlow(true); + runFlowAssertResponse(loadFile(expectedXmlFilename, substitutions)); + // Transfer should have been requested. + domain = reloadResourceByForeignKey(); + // Verify that HistoryEntry was created. + assertAboutDomains() + .that(domain) + .hasOneHistoryEntryEachOfTypes(DOMAIN_CREATE, DOMAIN_TRANSFER_REQUEST); + assertLastHistoryContainsResource(domain); + final HistoryEntry historyEntryTransferRequest = + getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_REQUEST); + assertAboutHistoryEntries() + .that(historyEntryTransferRequest) + .hasPeriodYears(1) + .and() + .hasOtherRegistrarId("TheRegistrar"); + // Verify correct fields were set. + assertTransferRequested( + domain, implicitTransferTime, Period.create(1, Unit.YEARS), expectedExpirationTime); + + subordinateHost = reloadResourceAndCloneAtTime(subordinateHost, clock.nowUtc()); + assertAboutHosts().that(subordinateHost).hasNoHistoryEntries(); + + assertHistoryEntriesContainBillingEventsAndGracePeriods( + expectedExpirationTime, + implicitTransferTime, + transferCost, + originalGracePeriods, + /* expectTransferBillingEvent= */ true, + extraExpectedBillingEvents); + + assertPollMessagesEmitted(expectedExpirationTime, implicitTransferTime); + assertAboutDomainAfterAutomaticTransfer( + expectedExpirationTime, implicitTransferTime, Period.create(1, Unit.YEARS)); + cloudTasksHelper.assertTasksEnqueued( + QUEUE_ASYNC_ACTIONS, + new TaskMatcher() + .path(ResaveEntityAction.PATH) + .method(HttpMethod.POST) + .service("backend") + .header("content-type", "application/x-www-form-urlencoded") + .param(PARAM_RESOURCE_KEY, domain.createVKey().stringify()) + .param(PARAM_REQUESTED_TIME, clock.nowUtc().toString()) + .scheduleTime(clock.nowUtc().plus(registry.getAutomaticTransferLength()))); + } + + private void doSuccessfulTest( + String commandFilename, String expectedXmlFilename, Map substitutions) + throws Exception { + clock.advanceOneMilli(); + doSuccessfulTest( + commandFilename, + expectedXmlFilename, + domain.getRegistrationExpirationTime().plusYears(1), + substitutions, + Optional.empty()); + } + + private void doSuccessfulTest(String commandFilename, String expectedXmlFilename) + throws Exception { + clock.advanceOneMilli(); + doSuccessfulTest( + commandFilename, expectedXmlFilename, domain.getRegistrationExpirationTime().plusYears(1)); + } + + private void doSuccessfulTest( + String commandFilename, + String expectedXmlFilename, + DateTime expectedExpirationTime, + BillingCancellation.Builder... extraExpectedBillingEvents) + throws Exception { + doSuccessfulTest( + commandFilename, + expectedXmlFilename, + expectedExpirationTime, + ImmutableMap.of(), + Optional.empty(), + extraExpectedBillingEvents); + } + + private void runWrongFeeAmountTest(Map substitutions) { + persistResource( + Tld.get("tld") + .asBuilder() + .setRenewBillingCostTransitions(ImmutableSortedMap.of(START_OF_TIME, Money.of(USD, 20))) + .build()); + EppException thrown = + assertThrows( + FeesMismatchException.class, + () -> doFailingTest("domain_transfer_request_fee.xml", substitutions)); + assertAboutEppExceptions().that(thrown).marshalsToXml(); + } + + private void runTest( + String commandFilename, UserPrivileges userPrivileges, Map substitutions) + throws Exception { + setEppInput(commandFilename, substitutions); + // Replace the ROID in the xml file with the one generated in our test. + eppLoader.replaceAll("JD1234-REP", contact.getRepoId()); + // Setup done; run the test. + assertMutatingFlow(true); + runFlow(CommitMode.LIVE, userPrivileges); + } + + private void runTest(String commandFilename, UserPrivileges userPrivileges) throws Exception { + runTest(commandFilename, userPrivileges, ImmutableMap.of()); + } + + private void doFailingTest(String commandFilename, Map substitutions) + throws Exception { + runTest(commandFilename, UserPrivileges.NORMAL, substitutions); + } + + private void doFailingTest(String commandFilename) throws Exception { + runTest(commandFilename, UserPrivileges.NORMAL, ImmutableMap.of()); + } + + /** Adds a domain with no pending transfer on it. */ + void setupDomain(String label, String tld) { + createTld(tld); + contact = persistActiveContact("jd1234"); + domain = + persistDomainWithDependentResources( + label, + tld, + contact, + clock.nowUtc(), + DateTime.parse("1999-04-03T22:00:00.0Z"), + REGISTRATION_EXPIRATION_TIME); + subordinateHost = + persistResource( + new Host.Builder() + .setRepoId("2-".concat(Ascii.toUpperCase(tld))) + .setHostName("ns1." + label + "." + tld) + .setPersistedCurrentSponsorRegistrarId("TheRegistrar") + .setCreationRegistrarId("TheRegistrar") + .setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z")) + .setSuperordinateDomain(domain.createVKey()) + .build()); + domain = + persistResource( + domain.asBuilder().addSubordinateHost(subordinateHost.getHostName()).build()); + historyEntryDomainCreate = + getOnlyHistoryEntryOfType(domain, DOMAIN_CREATE, DomainHistory.class); + } + + private void assertPollMessagesEmitted( + DateTime expectedExpirationTime, DateTime implicitTransferTime) { + // Assert that there exists a poll message to notify the losing registrar that a transfer was + // requested. If the implicit transfer time is now (i.e. the automatic transfer length is zero) + // then also expect a server approved poll message. + assertThat(getPollMessages("TheRegistrar", clock.nowUtc())) + .hasSize(implicitTransferTime.equals(clock.nowUtc()) ? 2 : 1); + + // Two poll messages on the gaining registrar's side at the expected expiration time: a + // (OneTime) transfer approved message, and an Autorenew poll message. + assertThat(getPollMessages("NewRegistrar", expectedExpirationTime)).hasSize(2); + PollMessage transferApprovedPollMessage = + getOnlyPollMessage("NewRegistrar", implicitTransferTime, PollMessage.OneTime.class); + PollMessage autorenewPollMessage = + getOnlyPollMessage("NewRegistrar", expectedExpirationTime, PollMessage.Autorenew.class); + assertThat(transferApprovedPollMessage.getEventTime()).isEqualTo(implicitTransferTime); + assertThat(autorenewPollMessage.getEventTime()).isEqualTo(expectedExpirationTime); + assertThat( + transferApprovedPollMessage.getResponseData().stream() + .filter(TransferResponse.class::isInstance) + .map(TransferResponse.class::cast) + .collect(onlyElement()) + .getTransferStatus()) + .isEqualTo(TransferStatus.SERVER_APPROVED); + PendingActionNotificationResponse panData = + transferApprovedPollMessage.getResponseData().stream() + .filter(PendingActionNotificationResponse.class::isInstance) + .map(PendingActionNotificationResponse.class::cast) + .collect(onlyElement()); + assertThat(panData.getTrid().getClientTransactionId()).hasValue("ABC-12345"); + assertThat(panData.getActionResult()).isTrue(); + + // Two poll messages on the losing registrar's side at the implicit transfer time: a + // transfer pending message, and a transfer approved message (both OneTime messages). + assertThat(getPollMessages("TheRegistrar", implicitTransferTime)).hasSize(2); + PollMessage losingTransferPendingPollMessage = + getPollMessages("TheRegistrar", clock.nowUtc()).stream() + .filter(pollMessage -> TransferStatus.PENDING.getMessage().equals(pollMessage.getMsg())) + .collect(onlyElement()); + PollMessage losingTransferApprovedPollMessage = + getPollMessages("TheRegistrar", implicitTransferTime).stream() + .filter(Predicates.not(Predicates.equalTo(losingTransferPendingPollMessage))) + .collect(onlyElement()); + assertThat(losingTransferPendingPollMessage.getEventTime()).isEqualTo(clock.nowUtc()); + assertThat(losingTransferApprovedPollMessage.getEventTime()).isEqualTo(implicitTransferTime); + assertThat( + losingTransferPendingPollMessage.getResponseData().stream() + .filter(TransferResponse.class::isInstance) + .map(TransferResponse.class::cast) + .collect(onlyElement()) + .getTransferStatus()) + .isEqualTo(TransferStatus.PENDING); + assertThat( + losingTransferApprovedPollMessage.getResponseData().stream() + .filter(TransferResponse.class::isInstance) + .map(TransferResponse.class::cast) + .collect(onlyElement()) + .getTransferStatus()) + .isEqualTo(TransferStatus.SERVER_APPROVED); + + // Assert that the poll messages show up in the TransferData server approve entities. + assertPollMessagesEqual( + loadByKey(domain.getTransferData().getServerApproveAutorenewPollMessage()), + autorenewPollMessage); + // Assert that the full set of server-approve poll messages is exactly the server approve + // OneTime messages to gaining and losing registrars plus the gaining client autorenew. + assertPollMessagesEqual( + Iterables.filter( + loadByKeys(domain.getTransferData().getServerApproveEntities()), PollMessage.class), + ImmutableList.of( + transferApprovedPollMessage, losingTransferApprovedPollMessage, autorenewPollMessage)); + } + + private void assertHistoryEntriesContainBillingEventsAndGracePeriods( + DateTime expectedExpirationTime, + DateTime implicitTransferTime, + Optional transferCost, + ImmutableSet originalGracePeriods, + boolean expectTransferBillingEvent, + BillingCancellation.Builder... extraExpectedBillingEvents) { + Tld registry = Tld.get(domain.getTld()); + final DomainHistory historyEntryTransferRequest = + getOnlyHistoryEntryOfType(domain, DOMAIN_TRANSFER_REQUEST, DomainHistory.class); + + // Construct the billing events we expect to exist, starting with the (optional) billing + // event for the transfer itself. + Optional optionalTransferBillingEvent; + if (expectTransferBillingEvent) { + // For normal transfers, a BillingEvent should be created AUTOMATIC_TRANSFER_DAYS in the + // future, for the case when the transfer is implicitly acked. + optionalTransferBillingEvent = + Optional.of( + new BillingEvent.Builder() + .setReason(Reason.TRANSFER) + .setTargetId(domain.getDomainName()) + .setEventTime(implicitTransferTime) + .setBillingTime( + implicitTransferTime.plus(registry.getTransferGracePeriodLength())) + .setRegistrarId("NewRegistrar") + .setCost(transferCost.orElse(Money.of(USD, 11))) + .setPeriodYears(1) + .setDomainHistory(historyEntryTransferRequest) + .build()); + } else { + // Superuser transfers with no bundled renewal have no transfer billing event. + optionalTransferBillingEvent = Optional.empty(); + } + // Construct the autorenew events for the losing/existing client and the gaining one. Note that + // all of the other transfer flow tests happen on day 3 of the transfer, but the initial + // request by definition takes place on day 1, so we need to edit the times in the + // autorenew events from the base test case. + BillingRecurrence losingClientAutorenew = + getLosingClientAutorenewEvent() + .asBuilder() + .setRecurrenceEndTime(implicitTransferTime) + .build(); + BillingRecurrence gainingClientAutorenew = + getGainingClientAutorenewEvent() + .asBuilder() + .setEventTime(expectedExpirationTime) + .setRecurrenceLastExpansion(expectedExpirationTime.minusYears(1)) + .build(); + // Construct extra billing events expected by the specific test. + ImmutableSet extraBillingBases = + Stream.of(extraExpectedBillingEvents) + .map(builder -> builder.setDomainHistory(historyEntryTransferRequest).build()) + .collect(toImmutableSet()); + // Assert that the billing events we constructed above actually exist in the database. + ImmutableSet expectedBillingBases = + Streams.concat( + Stream.of(losingClientAutorenew, gainingClientAutorenew), + optionalTransferBillingEvent.stream()) + .collect(toImmutableSet()); + assertBillingEvents(Sets.union(expectedBillingBases, extraBillingBases)); + // Assert that the domain's TransferData server-approve billing events match the above. + if (expectTransferBillingEvent) { + assertBillingEventsEqual( + loadByKey(domain.getTransferData().getServerApproveBillingEvent()), + optionalTransferBillingEvent.get()); + } else { + assertThat(domain.getTransferData().getServerApproveBillingEvent()).isNull(); + } + assertBillingEventsEqual( + loadByKey(domain.getTransferData().getServerApproveAutorenewEvent()), + gainingClientAutorenew); + // Assert that the full set of server-approve billing events is exactly the extra ones plus + // the transfer billing event (if present) and the gaining client autorenew. + ImmutableSet expectedServeApproveBillingBases = + Streams.concat(Stream.of(gainingClientAutorenew), optionalTransferBillingEvent.stream()) + .collect(toImmutableSet()); + assertBillingEventsEqual( + Iterables.filter( + loadByKeys(domain.getTransferData().getServerApproveEntities()), BillingBase.class), + Sets.union(expectedServeApproveBillingBases, extraBillingBases)); + // The domain's autorenew billing event should still point to the losing client's event. + BillingRecurrence domainAutorenewEvent = loadByKey(domain.getAutorenewBillingEvent()); + assertThat(domainAutorenewEvent.getRegistrarId()).isEqualTo("TheRegistrar"); + assertThat(domainAutorenewEvent.getRecurrenceEndTime()).isEqualTo(implicitTransferTime); + // The original grace periods should remain untouched. + assertThat(domain.getGracePeriods()).containsExactlyElementsIn(originalGracePeriods); + // If we fast forward AUTOMATIC_TRANSFER_DAYS, the transfer should have cleared out all other + // grace periods, but expect a transfer grace period (if there was a transfer billing event). + Domain domainAfterAutomaticTransfer = domain.cloneProjectedAtTime(implicitTransferTime); + if (expectTransferBillingEvent) { + assertGracePeriods( + domainAfterAutomaticTransfer.getGracePeriods(), + ImmutableMap.of( + GracePeriod.create( + GracePeriodStatus.TRANSFER, + domain.getRepoId(), + implicitTransferTime.plus(registry.getTransferGracePeriodLength()), + "NewRegistrar", + null), + optionalTransferBillingEvent.get())); + } else { + assertGracePeriods(domainAfterAutomaticTransfer.getGracePeriods(), ImmutableMap.of()); + } + } + + private BillingRecurrence getGainingClientAutorenewEvent() { + return new BillingRecurrence.Builder() + .setReason(Reason.RENEW) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId(domain.getDomainName()) + .setRegistrarId("NewRegistrar") + .setEventTime(EXTENDED_REGISTRATION_EXPIRATION_TIME) + .setRecurrenceEndTime(END_OF_TIME) + .setDomainHistory( + getOnlyHistoryEntryOfType( + domain, HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST, DomainHistory.class)) + .build(); + } + + /** Get the autorenew event that the losing client will have after a SERVER_APPROVED transfer. */ + private BillingRecurrence getLosingClientAutorenewEvent() { + return new BillingRecurrence.Builder() + .setReason(Reason.RENEW) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId(domain.getDomainName()) + .setRegistrarId("TheRegistrar") + .setEventTime(REGISTRATION_EXPIRATION_TIME) + .setRecurrenceEndTime(TRANSFER_EXPIRATION_TIME) + .setDomainHistory(historyEntryDomainCreate) + .build(); + } + + private void assertAboutDomainAfterAutomaticTransfer( + DateTime expectedExpirationTime, DateTime implicitTransferTime, Period expectedPeriod) + throws Exception { + Tld registry = Tld.get(domain.getTld()); + Domain domainAfterAutomaticTransfer = domain.cloneProjectedAtTime(implicitTransferTime); + assertTransferApproved(domainAfterAutomaticTransfer, implicitTransferTime, expectedPeriod); + assertAboutDomains() + .that(domainAfterAutomaticTransfer) + .hasRegistrationExpirationTime(expectedExpirationTime) + .and() + .hasLastEppUpdateTime(implicitTransferTime) + .and() + .hasLastEppUpdateRegistrarId("NewRegistrar"); + assertThat(loadByKey(domainAfterAutomaticTransfer.getAutorenewBillingEvent()).getEventTime()) + .isEqualTo(expectedExpirationTime); + // And after the expected grace time, the grace period should be gone. + Domain afterGracePeriod = + domain.cloneProjectedAtTime( + clock + .nowUtc() + .plus(registry.getAutomaticTransferLength()) + .plus(registry.getTransferGracePeriodLength())); + assertThat(afterGracePeriod.getGracePeriods()).isEmpty(); + } + + private void assertTransferApproved( + Domain domain, DateTime automaticTransferTime, Period expectedPeriod) throws Exception { + assertAboutDomains() + .that(domain) + .hasCurrentSponsorRegistrarId("NewRegistrar") + .and() + .hasLastTransferTime(automaticTransferTime) + .and() + .doesNotHaveStatusValue(StatusValue.PENDING_TRANSFER); + Trid expectedTrid = + Trid.create( + getClientTrid(), + domain.getTransferData().getTransferRequestTrid().getServerTransactionId()); + assertThat(domain.getTransferData()) + .isEqualTo( + new DomainTransferData.Builder() + .setGainingRegistrarId("NewRegistrar") + .setLosingRegistrarId("TheRegistrar") + .setTransferRequestTrid(expectedTrid) + .setTransferRequestTime(clock.nowUtc()) + .setTransferPeriod(expectedPeriod) + .setTransferStatus(TransferStatus.SERVER_APPROVED) + .setPendingTransferExpirationTime(automaticTransferTime) + .setTransferredRegistrationExpirationTime(domain.getRegistrationExpirationTime()) + // Server-approve entity fields should all be nulled out. + .build()); + } + + private void assertTransferRequested( + Domain domain, + DateTime automaticTransferTime, + Period expectedPeriod, + DateTime expectedExpirationTime) + throws Exception { + assertAboutDomains() + .that(domain) + .hasCurrentSponsorRegistrarId("TheRegistrar") + .and() + .hasStatusValue(StatusValue.PENDING_TRANSFER) + .and() + .hasLastEppUpdateTime(clock.nowUtc()) + .and() + .hasLastEppUpdateRegistrarId("NewRegistrar"); + Trid expectedTrid = + Trid.create( + getClientTrid(), + domain.getTransferData().getTransferRequestTrid().getServerTransactionId()); + assertThat(domain.getTransferData()) + .isEqualTo( + // Compare against only the following fields by rebuilding the existing TransferData. + // Equivalent to assertThat(transferData.getGainingClientId()).isEqualTo("NewReg") + // and similar individual assertions, but produces a nicer error message this way. + domain + .getTransferData() + .asBuilder() + .setGainingRegistrarId("NewRegistrar") + .setLosingRegistrarId("TheRegistrar") + .setTransferRequestTrid(expectedTrid) + .setTransferRequestTime(clock.nowUtc()) + .setTransferPeriod(expectedPeriod) + .setTransferStatus(TransferStatus.PENDING) + .setPendingTransferExpirationTime(automaticTransferTime) + .setTransferredRegistrationExpirationTime(expectedExpirationTime) + // Don't compare the server-approve entity fields; they're hard to reconstruct + // and logic later will check them. + .build()); + } +} diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java index f0f33b871..32f03c844 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java @@ -46,6 +46,7 @@ import static google.registry.testing.DomainSubject.assertAboutDomains; import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries; import static google.registry.testing.HostSubject.assertAboutHosts; +import static google.registry.testing.TestDataHelper.updateSubstitutions; import static google.registry.util.DateTimeUtils.START_OF_TIME; import static org.joda.money.CurrencyUnit.JPY; import static org.joda.money.CurrencyUnit.USD; @@ -146,32 +147,16 @@ class DomainTransferRequestFlowTest .put("AMOUNT", "11.00") .put("CURRENCY", "USD") .build(); - private static final ImmutableMap FEE_06_MAP = - new ImmutableMap.Builder() - .putAll(BASE_FEE_MAP) - .put("FEE_VERSION", "0.6") - .put("FEE_NS", "fee") - .build(); - private static final ImmutableMap FEE_11_MAP = - new ImmutableMap.Builder() - .putAll(BASE_FEE_MAP) - .put("FEE_VERSION", "0.11") - .put("FEE_NS", "fee11") - .build(); - private static final ImmutableMap FEE_12_MAP = - new ImmutableMap.Builder() - .putAll(BASE_FEE_MAP) - .put("FEE_VERSION", "0.12") - .put("FEE_NS", "fee12") - .build(); + private static final ImmutableMap FEE_STD_1_0_MAP = + updateSubstitutions(BASE_FEE_MAP, "FEE_VERSION", "epp:fee-1.0", "FEE_NS", "fee1_00"); private static final ImmutableMap RICH_DOMAIN_MAP = ImmutableMap.builder() .put("DOMAIN", "rich.example") .put("YEARS", "1") .put("AMOUNT", "100.00") .put("CURRENCY", "USD") - .put("FEE_VERSION", "0.12") - .put("FEE_NS", "fee12") + .put("FEE_VERSION", "epp:fee-1.0") + .put("FEE_NS", "fee") .build(); @BeforeEach @@ -665,140 +650,50 @@ class DomainTransferRequestFlowTest } @Test - void testSuccess_fee_v06() throws Exception { + void testSuccess_fee_std_v1() throws Exception { setupDomain("example", "tld"); doSuccessfulTest( - "domain_transfer_request_fee.xml", "domain_transfer_request_response_fee.xml", FEE_06_MAP); + "domain_transfer_request_fee.xml", + "domain_transfer_request_response_fee.xml", + FEE_STD_1_0_MAP); } @Test - void testSuccess_fee_v11() throws Exception { - setupDomain("example", "tld"); - doSuccessfulTest( - "domain_transfer_request_fee.xml", "domain_transfer_request_response_fee.xml", FEE_11_MAP); - } - - @Test - void testSuccess_fee_v12() throws Exception { - setupDomain("example", "tld"); - doSuccessfulTest( - "domain_transfer_request_fee.xml", "domain_transfer_request_response_fee.xml", FEE_12_MAP); - } - - @Test - void testSuccess_fee_withDefaultAttributes_v06() throws Exception { + void testSuccess_fee_withDefaultAttributes_std_v1() throws Exception { setupDomain("example", "tld"); doSuccessfulTest( "domain_transfer_request_fee_defaults.xml", "domain_transfer_request_response_fee.xml", - FEE_06_MAP); + FEE_STD_1_0_MAP); } @Test - void testSuccess_fee_withDefaultAttributes_v11() throws Exception { - setupDomain("example", "tld"); - doSuccessfulTest( - "domain_transfer_request_fee_defaults.xml", - "domain_transfer_request_response_fee.xml", - FEE_11_MAP); - } - - @Test - void testSuccess_fee_withDefaultAttributes_v12() throws Exception { - setupDomain("example", "tld"); - doSuccessfulTest( - "domain_transfer_request_fee_defaults.xml", - "domain_transfer_request_response_fee.xml", - FEE_12_MAP); - } - - @Test - void testFailure_refundableFee_v06() { + void testFailure_refundableFee_std_v1() { setupDomain("example", "tld"); EppException thrown = assertThrows( UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_refundable.xml", FEE_06_MAP)); + () -> doFailingTest("domain_transfer_request_fee_refundable.xml", FEE_STD_1_0_MAP)); assertAboutEppExceptions().that(thrown).marshalsToXml(); } @Test - void testFailure_refundableFee_v11() { + void testFailure_gracePeriodFee_std_v1() { setupDomain("example", "tld"); EppException thrown = assertThrows( UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_refundable.xml", FEE_11_MAP)); + () -> doFailingTest("domain_transfer_request_fee_grace_period.xml", FEE_STD_1_0_MAP)); assertAboutEppExceptions().that(thrown).marshalsToXml(); } @Test - void testFailure_refundableFee_v12() { + void testFailure_appliedFee_std_v1() { setupDomain("example", "tld"); EppException thrown = assertThrows( UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_refundable.xml", FEE_12_MAP)); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_gracePeriodFee_v06() { - setupDomain("example", "tld"); - EppException thrown = - assertThrows( - UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_grace_period.xml", FEE_06_MAP)); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_gracePeriodFee_v11() { - setupDomain("example", "tld"); - EppException thrown = - assertThrows( - UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_grace_period.xml", FEE_11_MAP)); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_gracePeriodFee_v12() { - setupDomain("example", "tld"); - EppException thrown = - assertThrows( - UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_grace_period.xml", FEE_12_MAP)); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_appliedFee_v06() { - setupDomain("example", "tld"); - EppException thrown = - assertThrows( - UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_applied.xml", FEE_06_MAP)); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_appliedFee_v11() { - setupDomain("example", "tld"); - EppException thrown = - assertThrows( - UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_applied.xml", FEE_11_MAP)); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_appliedFee_v12() { - setupDomain("example", "tld"); - EppException thrown = - assertThrows( - UnsupportedFeeAttributeException.class, - () -> doFailingTest("domain_transfer_request_fee_applied.xml", FEE_12_MAP)); + () -> doFailingTest("domain_transfer_request_fee_applied.xml", FEE_STD_1_0_MAP)); assertAboutEppExceptions().that(thrown).marshalsToXml(); } @@ -991,7 +886,7 @@ class DomainTransferRequestFlowTest } @Test - void testFailure_superuserExtension_zeroPeriod_feeTransferExtension() { + void testFailure_superuserExtension_zeroPeriod_feeTransferExtension_std_v1() { setupDomain("example", "tld"); eppRequestSource = EppRequestSource.TOOL; clock.advanceOneMilli(); @@ -1001,7 +896,11 @@ class DomainTransferRequestFlowTest runTest( "domain_transfer_request_fee_and_superuser_extension.xml", UserPrivileges.SUPERUSER, - ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "5"))); + new ImmutableMap.Builder() + .putAll(FEE_STD_1_0_MAP) + .put("PERIOD", "0") + .put("AUTOMATIC_TRANSFER_LENGTH", "5") + .build())); } @Test @@ -1063,7 +962,7 @@ class DomainTransferRequestFlowTest } @Test - void testSuccess_customLogicFee() throws Exception { + void testSuccess_customLogicFee_std_v1() throws Exception { setupDomain("expensive-domain", "foo"); clock.advanceOneMilli(); doSuccessfulTest( @@ -1075,7 +974,7 @@ class DomainTransferRequestFlowTest .put("YEARS", "1") .put("AMOUNT", "111.00") .put("EXDATE", "2002-09-08T22:00:00.0Z") - .put("FEE_VERSION", "0.6") + .put("FEE_VERSION", "epp:fee-1.0") .put("FEE_NS", "fee") .build(), Optional.of(Money.of(USD, 111))); @@ -1227,7 +1126,7 @@ class DomainTransferRequestFlowTest } @Test - void testSuccess_premiumNotBlocked() throws Exception { + void testSuccess_premiumNotBlocked_v06() throws Exception { setupDomain("rich", "example"); clock.advanceOneMilli(); // We don't verify the results; just check that the flow doesn't fail. @@ -1235,7 +1134,7 @@ class DomainTransferRequestFlowTest } @Test - void testSuccess_premiumNotBlockedInSuperuserMode() throws Exception { + void testSuccess_premiumNotBlockedInSuperuserMode_std_v1() throws Exception { setupDomain("rich", "example"); clock.advanceOneMilli(); // Modify the Registrar to block premium names. @@ -1525,24 +1424,14 @@ class DomainTransferRequestFlowTest } @Test - void testFailure_wrongCurrency_v06() { - runWrongCurrencyTest(FEE_06_MAP); - } - - @Test - void testFailure_wrongCurrency_v11() { - runWrongCurrencyTest(FEE_11_MAP); - } - - @Test - void testFailure_wrongCurrency_v12() { - runWrongCurrencyTest(FEE_12_MAP); + void testFailure_wrongCurrency_std_v1() { + runWrongCurrencyTest(FEE_STD_1_0_MAP); } @Test void testFailure_unknownCurrency() { Map substitutions = Maps.newHashMap(); - substitutions.putAll(FEE_06_MAP); + substitutions.putAll(FEE_STD_1_0_MAP); substitutions.put("CURRENCY", "BAD"); setupDomain("example", "tld"); setEppInput("domain_transfer_request_fee.xml", substitutions); @@ -1551,32 +1440,12 @@ class DomainTransferRequestFlowTest } @Test - void testFailure_feeGivenInWrongScale_v06() { + void testFailure_feeGivenInWrongScale_std_v1() { setupDomain("example", "tld"); EppException thrown = assertThrows( CurrencyValueScaleException.class, - () -> doFailingTest("domain_transfer_request_fee_bad_scale.xml", FEE_06_MAP)); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_feeGivenInWrongScale_v11() { - setupDomain("example", "tld"); - EppException thrown = - assertThrows( - CurrencyValueScaleException.class, - () -> doFailingTest("domain_transfer_request_fee_bad_scale.xml", FEE_11_MAP)); - assertAboutEppExceptions().that(thrown).marshalsToXml(); - } - - @Test - void testFailure_feeGivenInWrongScale_v12() { - setupDomain("example", "tld"); - EppException thrown = - assertThrows( - CurrencyValueScaleException.class, - () -> doFailingTest("domain_transfer_request_fee_bad_scale.xml", FEE_12_MAP)); + () -> doFailingTest("domain_transfer_request_fee_bad_scale.xml", FEE_STD_1_0_MAP)); assertAboutEppExceptions().that(thrown).marshalsToXml(); } @@ -1594,21 +1463,9 @@ class DomainTransferRequestFlowTest } @Test - void testFailure_wrongFeeAmount_v06() { + void testFailure_wrongFeeAmount_std_v1() { setupDomain("example", "tld"); - runWrongFeeAmountTest(FEE_06_MAP); - } - - @Test - void testFailure_wrongFeeAmount_v11() { - setupDomain("example", "tld"); - runWrongFeeAmountTest(FEE_11_MAP); - } - - @Test - void testFailure_wrongFeeAmount_v12() { - setupDomain("example", "tld"); - runWrongFeeAmountTest(FEE_12_MAP); + runWrongFeeAmountTest(FEE_STD_1_0_MAP); } @Test diff --git a/core/src/test/java/google/registry/flows/domain/DomainUpdateFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainUpdateFlowTest.java index 2799a0462..35fc786d8 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainUpdateFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainUpdateFlowTest.java @@ -72,7 +72,6 @@ import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException; import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException; import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException; import google.registry.flows.domain.DomainFlowUtils.EmptySecDnsUpdateException; -import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException; import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForNonFreeOperationException; import google.registry.flows.domain.DomainFlowUtils.InvalidDsRecordException; import google.registry.flows.domain.DomainFlowUtils.LinkedResourceInPendingDeleteProhibitsOperationException; @@ -359,10 +358,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCaseThese are enabled only in the production environment so in order to test them, we need to + * simulate the production environment for each test (and reset it to the test environment + * afterward). + */ +public abstract class ProductionSimulatingFeeExtensionsTest + extends ResourceFlowTestCase { + + private RegistryEnvironment previousEnvironment; + + @BeforeEach + void beforeEach() { + previousEnvironment = RegistryEnvironment.get(); + RegistryEnvironment.PRODUCTION.setup(); + reloadServiceExtensionUris(); + } + + @AfterEach + void afterEach() { + previousEnvironment.setup(); + reloadServiceExtensionUris(); + } + + void reloadServiceExtensionUris() { + ProtocolDefinition.reloadServiceExtensionUris(); + sessionMetadata.setServiceExtensionUris(ProtocolDefinition.getVisibleServiceExtensionUris()); + EppXmlTransformer.reloadTransformers(); + } +} diff --git a/core/src/test/java/google/registry/model/ResourceCommandTestCase.java b/core/src/test/java/google/registry/model/ResourceCommandTestCase.java index aed5e9bc8..9d037dc5b 100644 --- a/core/src/test/java/google/registry/model/ResourceCommandTestCase.java +++ b/core/src/test/java/google/registry/model/ResourceCommandTestCase.java @@ -24,12 +24,9 @@ import google.registry.testing.EppLoader; /** Unit tests for {@code ResourceCommand}. */ public abstract class ResourceCommandTestCase extends EntityTestCase { - protected void doXmlRoundtripTest(String inputFilename, String... ignoredPaths) - throws Exception { + protected void doXmlRoundtripTest(String inputFilename) throws Exception { EppLoader eppLoader = new EppLoader(this, inputFilename); assertXmlEquals( - eppLoader.getEppXml(), - new String(marshalInput(eppLoader.getEpp(), STRICT), UTF_8), - ignoredPaths); + eppLoader.getEppXml(), new String(marshalInput(eppLoader.getEpp(), STRICT), UTF_8)); } } diff --git a/core/src/test/java/google/registry/model/domain/DomainCommandTest.java b/core/src/test/java/google/registry/model/domain/DomainCommandTest.java index fa0e733b5..17f0fb2d0 100644 --- a/core/src/test/java/google/registry/model/domain/DomainCommandTest.java +++ b/core/src/test/java/google/registry/model/domain/DomainCommandTest.java @@ -113,11 +113,6 @@ class DomainCommandTest extends ResourceCommandTestCase { doXmlRoundtripTest("domain_update.xml"); } - @Test - void testUpdate_fee() throws Exception { - doXmlRoundtripTest("domain_update_fee.xml"); - } - @Test void testUpdate_emptyCommand() throws Exception { // This EPP command wouldn't be allowed for policy reasons, but should marshal/unmarshal fine. @@ -153,11 +148,6 @@ class DomainCommandTest extends ResourceCommandTestCase { doXmlRoundtripTest("domain_info_sunrise.xml"); } - @Test - void testInfo_feeExtension() throws Exception { - doXmlRoundtripTest("domain_info_fee.xml"); - } - @Test void testCheck() throws Exception { doXmlRoundtripTest("domain_check.xml"); diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_anchor_response_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_anchor_response_stdv1.xml new file mode 100644 index 000000000..22dd8fe96 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_anchor_response_stdv1.xml @@ -0,0 +1,92 @@ + + + + Command completed successfully + + + + + example1.tld + + + example2.example + Alloc token invalid for domain + + + reserved.tld + Alloc token invalid for domain + + + rich.example + Alloc token invalid for domain + + + + + + USD + + example1.tld + + 1 + 0.00 + + + + example2.example + token-not-supported + + 1 + + + + reserved.tld + token-not-supported + + 1 + + + + rich.example + token-not-supported + + 1 + + + + example1.tld + premium + + 1 + 11.00 + + + + example2.example + token-not-supported + + 1 + + + + reserved.tld + token-not-supported + + 1 + + + + rich.example + token-not-supported + + 1 + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_anchor_response.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_anchor_response_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_anchor_response.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_anchor_response_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_response_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_response_stdv1.xml new file mode 100644 index 000000000..66bbf3875 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_response_stdv1.xml @@ -0,0 +1,91 @@ + + + + Command completed successfully + + + + + example1.tld + + + example2.example + + + reserved.tld + Reserved + + + rich.example + + + + + + USD + + example2.example + + 1 + 6.50 + + + + example1.tld + + 1 + 6.50 + + + + reserved.tld + reserved + + 1 + + + + rich.example + premium + + 1 + 100.00 + + + + example1.tld + + 1 + 11.00 + + + + example2.example + + 1 + 11.00 + + + + reserved.tld + + 1 + 11.00 + + + + rich.example + premium + + 1 + 100.00 + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_response.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_response_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_response.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_response_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_response_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_response_stdv1.xml new file mode 100644 index 000000000..dfb2e9436 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_response_stdv1.xml @@ -0,0 +1,63 @@ + + + + Command completed successfully + + + + + example1.tld + Alloc token invalid for domain + + + example2.example + Alloc token invalid for domain + + + reserved.tld + Alloc token invalid for domain + + + specificuse.tld + + + + + + USD + + example1.tld + token-not-supported + + 1 + + + + example2.example + token-not-supported + + 1 + + + + reserved.tld + token-not-supported + + 1 + + + + specificuse.tld + + 1 + 13.00 + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_response.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_response_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_response.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_response_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_stdv1.xml new file mode 100644 index 000000000..1e90aafa0 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_stdv1.xml @@ -0,0 +1,26 @@ + + + + + example1.tld + example2.example + reserved.tld + specificuse.tld + + + + + abc123 + + + USD + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_specificuse_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_stdv1.xml new file mode 100644 index 000000000..719da5ccf --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_stdv1.xml @@ -0,0 +1,27 @@ + + + + + example1.tld + example2.example + reserved.tld + rich.example + + + + + abc123 + + + USD + + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_fee_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_multiname_promotion.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_multiname_promotion.xml index 973b9ad02..a30850257 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_multiname_promotion.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_multiname_promotion.xml @@ -17,4 +17,4 @@ ABC-12345 - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_response_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_response_stdv1.xml new file mode 100644 index 000000000..11270f444 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_response_stdv1.xml @@ -0,0 +1,47 @@ + + + + Command completed successfully + + + + + %DOMAIN% + + + + + + USD + + %DOMAIN% + %FEE_CLASS% + + 1 + %COST_1YR% + + + + %DOMAIN% + %FEE_CLASS% + + 2 + %COST_2YR% + + + + %DOMAIN% + %FEE_CLASS% + + 5 + %COST_5YR% + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_response.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_response_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_response.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_response_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_stdv1.xml new file mode 100644 index 000000000..fbaf5611a --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_stdv1.xml @@ -0,0 +1,31 @@ + + + + + %DOMAIN% + + + + + abc123 + + + USD + + 1 + + + 2 + + + 5 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_allocationtoken_promotion_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_bad_currency_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_bad_currency_stdv1.xml new file mode 100644 index 000000000..e24d8b02c --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_bad_currency_stdv1.xml @@ -0,0 +1,23 @@ + + + + + example1.tld + example2.tld + example3.tld + + + + + custom + + + BAD + + 1 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_bad_period_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_bad_period_stdv1.xml new file mode 100644 index 000000000..ccd8d375c --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_bad_period_stdv1.xml @@ -0,0 +1,18 @@ + + + + + example1.tld + + + + + USD + + 1 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_command_phase_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_command_phase_stdv1.xml new file mode 100644 index 000000000..fc43631bc --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_command_phase_stdv1.xml @@ -0,0 +1,15 @@ + + + + + example1.tld + + + + + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_command_subphase_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_command_subphase_stdv1.xml new file mode 100644 index 000000000..a909e0201 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_command_subphase_stdv1.xml @@ -0,0 +1,15 @@ + + + + + example1.tld + + + + + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_euro_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_euro_stdv1.xml new file mode 100644 index 000000000..8bf0b9666 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_euro_stdv1.xml @@ -0,0 +1,23 @@ + + + + + example1.tld + example2.tld + example3.tld + + + + + custom + + + EUR + + 1 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_response_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_response_stdv1.xml new file mode 100644 index 000000000..1bb852ea1 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_response_stdv1.xml @@ -0,0 +1,30 @@ + + + + Command completed successfully + + + + + example1.tld + + + + + + USD + + example1.tld + + 1 + 11.10 + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_response.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_response_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_response.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_response_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_stdv1.xml new file mode 100644 index 000000000..13870806b --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_stdv1.xml @@ -0,0 +1,21 @@ + + + + + example1.tld + + + + + custom + + + USD + + 1 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_fee_fractional_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_invalid_command_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_invalid_command_stdv1.xml index 5f6ecab10..efd77ced3 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_invalid_command_stdv1.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_invalid_command_stdv1.xml @@ -6,7 +6,7 @@ - + 1 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_allocationtoken_v06.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_allocationtoken_v06.xml index 9e362c8f4..946918932 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_allocationtoken_v06.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_commands_allocationtoken_v06.xml @@ -36,4 +36,4 @@ ABC-12345 - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_response_v12.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_response_v12.xml index 7e946c1b5..88f421d15 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_response_v12.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiple_currencies_response_v12.xml @@ -42,4 +42,4 @@ server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiyear_restore_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiyear_restore_stdv1.xml new file mode 100644 index 000000000..f5bfcec35 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiyear_restore_stdv1.xml @@ -0,0 +1,20 @@ + + + + + example1.tld + + + + + custom + + + + 2 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiyear_transfer_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiyear_transfer_stdv1.xml new file mode 100644 index 000000000..57eef023a --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_multiyear_transfer_stdv1.xml @@ -0,0 +1,20 @@ + + + + + example1.tld + + + + + custom + + + + 2 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_thirty_domains_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_thirty_domains_stdv1.xml new file mode 100644 index 000000000..c48188d66 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_thirty_domains_stdv1.xml @@ -0,0 +1,378 @@ + + + + Command completed successfully + + + + + example-00.tld + + + example-01.tld + In use + + + example-02.tld + In use + + + example-03.tld + In use + + + example-04.tld + In use + + + example-05.tld + In use + + + example-06.tld + In use + + + example-07.tld + In use + + + example-08.tld + In use + + + example-09.tld + In use + + + example-10.tld + In use + + + example-11.tld + In use + + + example-12.tld + In use + + + example-13.tld + In use + + + example-14.tld + In use + + + example-15.tld + In use + + + example-16.tld + In use + + + example-17.tld + In use + + + example-18.tld + In use + + + example-19.tld + In use + + + example-20.tld + In use + + + example-21.tld + In use + + + example-22.tld + In use + + + example-23.tld + In use + + + example-24.tld + In use + + + example-25.tld + In use + + + example-26.tld + In use + + + example-27.tld + In use + + + example-28.tld + In use + + + example-29.tld + In use + + + + + + USD + + example-00.tld + + 1 + 17.00 + + + + example-01.tld + + 1 + 17.00 + 11.00 + + + + example-02.tld + + 1 + 17.00 + 11.00 + + + + example-03.tld + + 1 + 17.00 + 11.00 + + + + example-04.tld + + 1 + 17.00 + 11.00 + + + + example-05.tld + + 1 + 17.00 + 11.00 + + + + example-06.tld + + 1 + 17.00 + 11.00 + + + + example-07.tld + + 1 + 17.00 + 11.00 + + + + example-08.tld + + 1 + 17.00 + 11.00 + + + + example-09.tld + + 1 + 17.00 + 11.00 + + + + example-10.tld + + 1 + 17.00 + 11.00 + + + + example-11.tld + + 1 + 17.00 + 11.00 + + + + example-12.tld + + 1 + 17.00 + 11.00 + + + + example-13.tld + + 1 + 17.00 + 11.00 + + + + example-14.tld + + 1 + 17.00 + 11.00 + + + + example-15.tld + + 1 + 17.00 + 11.00 + + + + example-16.tld + + 1 + 17.00 + 11.00 + + + + example-17.tld + + 1 + 17.00 + 11.00 + + + + example-18.tld + + 1 + 17.00 + 11.00 + + + + example-19.tld + + 1 + 17.00 + 11.00 + + + + example-20.tld + + 1 + 17.00 + 11.00 + + + + example-21.tld + + 1 + 17.00 + 11.00 + + + + example-22.tld + + 1 + 17.00 + 11.00 + + + + example-23.tld + + 1 + 17.00 + 11.00 + + + + example-24.tld + + 1 + 17.00 + 11.00 + + + + example-25.tld + + 1 + 17.00 + 11.00 + + + + example-26.tld + + 1 + 17.00 + 11.00 + + + + example-27.tld + + 1 + 17.00 + 11.00 + + + + example-28.tld + + 1 + 17.00 + 11.00 + + + + example-29.tld + + 1 + 17.00 + 11.00 + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_thirty_domains.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_thirty_domains_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_thirty_domains.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_fee_response_thirty_domains_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_thirty_domains_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_thirty_domains_stdv1.xml new file mode 100644 index 000000000..cd254df0e --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_thirty_domains_stdv1.xml @@ -0,0 +1,48 @@ + + + + + example-00.tld + example-01.tld + example-02.tld + example-03.tld + example-04.tld + example-05.tld + example-06.tld + example-07.tld + example-08.tld + example-09.tld + example-10.tld + example-11.tld + example-12.tld + example-13.tld + example-14.tld + example-15.tld + example-16.tld + example-17.tld + example-18.tld + example-19.tld + example-20.tld + example-21.tld + example-22.tld + example-23.tld + example-24.tld + example-25.tld + example-26.tld + example-27.tld + example-28.tld + example-29.tld + + + + + custom + + + USD + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_thirty_domains.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_thirty_domains_v06.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_check_fee_thirty_domains.xml rename to core/src/test/resources/google/registry/flows/domain/domain_check_fee_thirty_domains_v06.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_fee_unknown_command_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_unknown_command_stdv1.xml new file mode 100644 index 000000000..27a9e70d4 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_fee_unknown_command_stdv1.xml @@ -0,0 +1,17 @@ + + + + + example1.tld + + + + + + 1 + + + + ABC-12345 + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_tiered_promotion_fee_response_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_tiered_promotion_fee_response_stdv1.xml new file mode 100644 index 000000000..ecce532ae --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_tiered_promotion_fee_response_stdv1.xml @@ -0,0 +1,78 @@ + + + + Command completed successfully + + + + + example1.tld + In use + + + example2.tld + + + example3.tld + + + + + + USD + + example1.tld + STANDARD + + 1 + 13.00 + + + + example1.tld + STANDARD PROMOTION + + 1 + 6.50 + + + + example2.tld + STANDARD + + 1 + 13.00 + + + + example2.tld + STANDARD PROMOTION + + 1 + 6.50 + + + + example3.tld + STANDARD + + 1 + 13.00 + + + + example3.tld + STANDARD PROMOTION + + 1 + 6.50 + + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_check_tiered_promotion_fee_response_v12.xml b/core/src/test/resources/google/registry/flows/domain/domain_check_tiered_promotion_fee_response_v12.xml index 56602f872..63dcdda94 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_check_tiered_promotion_fee_response_v12.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_check_tiered_promotion_fee_response_v12.xml @@ -88,4 +88,4 @@ server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_eap_combined_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_eap_combined_fee.xml index cc26d577e..05d3c31db 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_eap_combined_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_eap_combined_fee.xml @@ -10,7 +10,7 @@ - + USD 126.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_eap_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_eap_fee.xml index 5743b50ae..cda7b556c 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_eap_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_eap_fee.xml @@ -15,7 +15,7 @@ - + USD 24.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_extra_fees.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_extra_fees.xml index aa09f34e1..2f752a500 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_extra_fees.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_extra_fees.xml @@ -15,7 +15,7 @@ - + USD %FEE_1% %FEE_2% diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_fee.xml index 96437ed56..c2abd2153 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_fee.xml @@ -15,7 +15,7 @@ - + %CURRENCY% 24.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_applied.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_applied.xml index d40fd7c30..8b5b61f59 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_applied.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_applied.xml @@ -15,7 +15,7 @@ - + USD 26.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_bad_scale.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_bad_scale.xml index cfa201059..f7ea757e9 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_bad_scale.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_bad_scale.xml @@ -15,7 +15,7 @@ - + USD 26.000 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_defaults.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_defaults.xml index 0dd8dea31..2e3b9facc 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_defaults.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_defaults.xml @@ -15,7 +15,7 @@ - + USD 24.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_grace_period.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_grace_period.xml index 833ce2717..1afb27a68 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_grace_period.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_grace_period.xml @@ -15,7 +15,7 @@ - + USD 26.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_refundable.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_refundable.xml index 4534c4892..c8d6e255b 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_fee_refundable.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_fee_refundable.xml @@ -15,7 +15,7 @@ - + USD 26.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_nonpremium_token_response.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_nonpremium_token_response.xml index 636d2e5f6..41de78b7d 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_nonpremium_token_response.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_nonpremium_token_response.xml @@ -1,7 +1,4 @@ - - + Command completed successfully @@ -14,14 +11,14 @@ - - USD - 13.00 - + + USD + 13.00 + ABC-12345 server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_premium.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_premium.xml index 8385ac6db..e2ea97925 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_premium.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_premium.xml @@ -15,7 +15,7 @@ - + USD 200.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_premium_allocationtoken.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_premium_allocationtoken.xml index 80cb8ac59..ad1d37aee 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_premium_allocationtoken.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_premium_allocationtoken.xml @@ -20,7 +20,7 @@ "urn:ietf:params:xml:ns:allocationToken-1.0"> abc123 - + USD %FEE% diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_premium_eap.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_premium_eap.xml index cfc54f7a0..00a384d34 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_premium_eap.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_premium_eap.xml @@ -15,7 +15,7 @@ - + USD 200.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_response_eap_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_response_eap_fee.xml index f573fb789..666fa5c05 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_response_eap_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_response_eap_fee.xml @@ -12,7 +12,7 @@ - + USD 24.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_response_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_response_fee.xml index b04dc8598..6e3ad40b2 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_response_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_response_fee.xml @@ -12,7 +12,7 @@ - + USD %FEE% diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_response_premium.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_response_premium.xml index 044159c38..44177b705 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_response_premium.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_response_premium.xml @@ -12,7 +12,7 @@ - + USD %FEE% diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_response_premium_eap.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_response_premium_eap.xml index b5bdbc0bf..5ac9f9c6d 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_create_response_premium_eap.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_create_response_premium_eap.xml @@ -6,13 +6,13 @@ - %DOMAIN% + rich.example 1999-04-03T22:00:00.0Z 2001-04-03T22:00:00.0Z - + USD 200.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_delete_response_autorenew_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_autorenew_fee.xml index 6621b208b..557fae87c 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_delete_response_autorenew_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_autorenew_fee.xml @@ -5,7 +5,7 @@ + xmlns:fee="urn:ietf:params:xml:ns:%FEE_VERSION%"> USD -11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee.xml index fec4d5b39..3f2262a6e 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee.xml @@ -5,7 +5,7 @@ + xmlns:fee="urn:ietf:params:xml:ns:%FEE_VERSION%"> USD -123.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee_free_grace_stdv1.xml b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee_free_grace_stdv1.xml new file mode 100644 index 000000000..fef00f075 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee_free_grace_stdv1.xml @@ -0,0 +1,18 @@ + + + + Command completed successfully + + + + USD + 0.00 + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee_free_grace.xml b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee_free_grace_v12.xml similarity index 100% rename from core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee_free_grace.xml rename to core/src/test/resources/google/registry/flows/domain/domain_delete_response_fee_free_grace_v12.xml diff --git a/core/src/test/resources/google/registry/flows/domain/domain_delete_response_pending_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_pending_fee.xml index beac5dee4..f05cbd163 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_delete_response_pending_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_delete_response_pending_fee.xml @@ -5,7 +5,7 @@ + xmlns:fee="urn:ietf:params:xml:ns:%FEE_VERSION%"> USD -456.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee.xml index f019a8e03..452f7aa82 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee.xml @@ -9,7 +9,7 @@ - + %CURRENCY% %FEE% diff --git a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_applied.xml b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_applied.xml index 8958c7ca1..91737c825 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_applied.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_applied.xml @@ -9,7 +9,7 @@ - + USD 55.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_bad_scale.xml b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_bad_scale.xml index f8c9ca2e9..23cd4d4f8 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_bad_scale.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_bad_scale.xml @@ -9,7 +9,7 @@ - + USD 55.000 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_defaults.xml b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_defaults.xml index 0764023fd..e207f8037 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_defaults.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_defaults.xml @@ -9,7 +9,7 @@ - + USD 55.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_grace_period.xml b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_grace_period.xml index ae579877c..93dade4ba 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_grace_period.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_grace_period.xml @@ -9,7 +9,7 @@ - + USD 55.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_refundable.xml b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_refundable.xml index aa9f2b594..d529fe018 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_refundable.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_renew_fee_refundable.xml @@ -9,7 +9,7 @@ - + USD 55.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_renew_response_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_renew_response_fee.xml index 6c28a2fde..33b13b344 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_renew_response_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_renew_response_fee.xml @@ -11,7 +11,7 @@ - <%FEE_NS%:renData xmlns:%FEE_NS%="urn:ietf:params:xml:ns:fee-%FEE_VERSION%"> + <%FEE_NS%:renData xmlns:%FEE_NS%="urn:ietf:params:xml:ns:%FEE_VERSION%"> <%FEE_NS%:currency>%CURRENCY% <%FEE_NS%:fee description="renew">%FEE% diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_approve_allocation_token.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_approve_allocation_token.xml index acc406606..1d9323fff 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_approve_allocation_token.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_approve_allocation_token.xml @@ -15,4 +15,4 @@ ABC-12345 - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee.xml index 5fc8d376e..32ffebcd2 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee.xml @@ -11,7 +11,7 @@ - + %CURRENCY% %AMOUNT% diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_and_superuser_extension.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_and_superuser_extension.xml index ad0a02cc7..c6348172f 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_and_superuser_extension.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_and_superuser_extension.xml @@ -10,7 +10,7 @@ - + USD 11 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_applied.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_applied.xml index bb03ccd2e..ace1d334e 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_applied.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_applied.xml @@ -11,7 +11,7 @@ - + USD 11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_bad_scale.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_bad_scale.xml index 6c7aeeb96..cb0f8e0ee 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_bad_scale.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_bad_scale.xml @@ -11,7 +11,7 @@ - + USD 11.000 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_defaults.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_defaults.xml index 7fb050f24..3c8dd6489 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_defaults.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_defaults.xml @@ -11,7 +11,7 @@ - + USD 11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_grace_period.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_grace_period.xml index 58d69f9f8..1b25e1302 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_grace_period.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_grace_period.xml @@ -11,7 +11,7 @@ - + USD 11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_refundable.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_refundable.xml index ed5efc602..097132cc0 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_refundable.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_refundable.xml @@ -11,7 +11,7 @@ - + USD 11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_fee.xml index 32e255fd1..e47114f9b 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_fee.xml @@ -16,7 +16,7 @@ - + USD 11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_fees.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_fees.xml index da7f26795..e9118e7c3 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_fees.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_fees.xml @@ -16,7 +16,7 @@ - + USD 11.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_separate_fees.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_separate_fees.xml index 281506964..44e733a2a 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_separate_fees.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_separate_fees.xml @@ -11,7 +11,7 @@ - + USD 11.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_fee.xml deleted file mode 100644 index 0da213979..000000000 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_fee.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - example.tld - - - - - 2BARfoo - - - - - - - USD - 5.00 - - - ABC-12345 - - diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee.xml index 23e4cc7d7..c97039851 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee.xml @@ -11,7 +11,7 @@ - + %CURRENCY% 17.00 11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_applied.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_applied.xml index e13629610..2dbc7156c 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_applied.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_applied.xml @@ -11,7 +11,7 @@ - + USD 28.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_bad_scale.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_bad_scale.xml index 27658c3c5..4ed85e057 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_bad_scale.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_bad_scale.xml @@ -11,7 +11,7 @@ - + USD 28.000 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_defaults.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_defaults.xml index ec3310945..82e1b3654 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_defaults.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_defaults.xml @@ -11,7 +11,7 @@ - + USD 11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_grace_period.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_grace_period.xml index 0e76e515b..91c522d7d 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_grace_period.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_grace_period.xml @@ -11,7 +11,7 @@ - + USD 28.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_no_renewal.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_no_renewal.xml index 78a05ae98..9a30554d5 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_no_renewal.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_no_renewal.xml @@ -11,7 +11,7 @@ - + %CURRENCY% 17.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_refundable.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_refundable.xml index 4c15009ae..fff2320be 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_refundable.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_fee_refundable.xml @@ -11,7 +11,7 @@ - + USD 28.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_premium.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_premium.xml index 4b633f0fa..5f10baaa2 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_premium.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_premium.xml @@ -11,7 +11,7 @@ - + USD 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_premium_no_renewal.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_premium_no_renewal.xml index 5bbcf6bc6..0c1e432be 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_premium_no_renewal.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_premium_no_renewal.xml @@ -11,7 +11,7 @@ - + USD 17.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_fee.xml index 422c9cdd7..610be5b10 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_fee.xml @@ -4,7 +4,7 @@ Command completed successfully - <%FEE_NS%:updData xmlns:%FEE_NS%="urn:ietf:params:xml:ns:fee-%FEE_VERSION%"> + <%FEE_NS%:updData xmlns:%FEE_NS%="urn:ietf:params:xml:ns:%FEE_VERSION%"> <%FEE_NS%:currency>USD <%FEE_NS%:fee description="restore">17.00 <%FEE_NS%:fee description="renew">11.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_fee_no_renewal.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_fee_no_renewal.xml index 05484e809..b86396dd1 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_fee_no_renewal.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_fee_no_renewal.xml @@ -4,7 +4,7 @@ Command completed successfully - <%FEE_NS%:updData xmlns:%FEE_NS%="urn:ietf:params:xml:ns:fee-%FEE_VERSION%"> + <%FEE_NS%:updData xmlns:%FEE_NS%="urn:ietf:params:xml:ns:%FEE_VERSION%"> <%FEE_NS%:currency>USD <%FEE_NS%:fee description="restore">17.00 diff --git a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_premium.xml b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_premium.xml index 7e60f773a..c70c04d04 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_premium.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_update_restore_request_response_premium.xml @@ -4,7 +4,7 @@ Command completed successfully - + USD 17.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain_check_fee_premium.xml b/core/src/test/resources/google/registry/flows/domain_check_fee_premium.xml index dd0c9e980..265bb2314 100644 --- a/core/src/test/resources/google/registry/flows/domain_check_fee_premium.xml +++ b/core/src/test/resources/google/registry/flows/domain_check_fee_premium.xml @@ -6,11 +6,9 @@ - - - rich.example - create - + + USD + ABC-12345 diff --git a/core/src/test/resources/google/registry/flows/domain_check_fee_premium_response.xml b/core/src/test/resources/google/registry/flows/domain_check_fee_premium_response.xml index 5f55a39ea..b038450f2 100644 --- a/core/src/test/resources/google/registry/flows/domain_check_fee_premium_response.xml +++ b/core/src/test/resources/google/registry/flows/domain_check_fee_premium_response.xml @@ -11,14 +11,15 @@ - - - rich.example - USD - create - 1 - 100.00 + + USD + + rich.example premium + + 1 + 100.00 + diff --git a/core/src/test/resources/google/registry/flows/domain_create_eap_fee.xml b/core/src/test/resources/google/registry/flows/domain_create_eap_fee.xml index eebb13ac2..1431e610c 100644 --- a/core/src/test/resources/google/registry/flows/domain_create_eap_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain_create_eap_fee.xml @@ -10,7 +10,7 @@ - + USD 24.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain_create_response_eap_fee.xml b/core/src/test/resources/google/registry/flows/domain_create_response_eap_fee.xml index a2ff9ca6b..b2c05ee93 100644 --- a/core/src/test/resources/google/registry/flows/domain_create_response_eap_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain_create_response_eap_fee.xml @@ -11,7 +11,7 @@ - + USD 24.00 100.00 diff --git a/core/src/test/resources/google/registry/flows/domain_delete_response_fee.xml b/core/src/test/resources/google/registry/flows/domain_delete_response_fee.xml index d9f6998d4..25d9cef67 100644 --- a/core/src/test/resources/google/registry/flows/domain_delete_response_fee.xml +++ b/core/src/test/resources/google/registry/flows/domain_delete_response_fee.xml @@ -5,7 +5,7 @@ + xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0"> USD -24.00 diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_after_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_after_argp.xml index 83ef3258e..3d4511058 100644 --- a/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_after_argp.xml +++ b/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_after_argp.xml @@ -30,4 +30,4 @@ server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_during_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_during_argp.xml index e5c4e0ee9..e40b44951 100644 --- a/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_during_argp.xml +++ b/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_during_argp.xml @@ -34,4 +34,4 @@ server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_during_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_during_argp.xml index d3d6b55d9..a31238daa 100644 --- a/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_during_argp.xml +++ b/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_during_argp.xml @@ -33,4 +33,4 @@ server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_during_transfer_during_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_during_transfer_during_argp.xml index 2fc680574..9a2797b64 100644 --- a/core/src/test/resources/google/registry/flows/domain_info_response_during_transfer_during_argp.xml +++ b/core/src/test/resources/google/registry/flows/domain_info_response_during_transfer_during_argp.xml @@ -33,4 +33,4 @@ server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard.xml b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard.xml index bb38fca6d..b9dbf20e8 100644 --- a/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard.xml +++ b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard.xml @@ -19,4 +19,4 @@ server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard_not_requested.xml b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard_not_requested.xml index 054cdb4a2..c159d4d88 100644 --- a/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard_not_requested.xml +++ b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard_not_requested.xml @@ -8,4 +8,4 @@ server-trid - \ No newline at end of file + diff --git a/core/src/test/resources/google/registry/flows/greeting.xml b/core/src/test/resources/google/registry/flows/greeting.xml index 4482b7f27..7e303503a 100644 --- a/core/src/test/resources/google/registry/flows/greeting.xml +++ b/core/src/test/resources/google/registry/flows/greeting.xml @@ -11,9 +11,6 @@ urn:ietf:params:xml:ns:launch-1.0 urn:ietf:params:xml:ns:rgp-1.0 urn:ietf:params:xml:ns:secDNS-1.1 - urn:ietf:params:xml:ns:fee-0.6 - urn:ietf:params:xml:ns:fee-0.11 - urn:ietf:params:xml:ns:fee-0.12 urn:ietf:params:xml:ns:epp:fee-1.0 diff --git a/core/src/test/resources/google/registry/flows/login_valid_fee_extension.xml b/core/src/test/resources/google/registry/flows/login_valid_fee_extension.xml index d5278b542..f46647f74 100644 --- a/core/src/test/resources/google/registry/flows/login_valid_fee_extension.xml +++ b/core/src/test/resources/google/registry/flows/login_valid_fee_extension.xml @@ -13,7 +13,7 @@ urn:ietf:params:xml:ns:launch-1.0 urn:ietf:params:xml:ns:rgp-1.0 - urn:ietf:params:xml:ns:fee-0.6 + urn:ietf:params:xml:ns:epp:fee-1.0 diff --git a/core/src/test/resources/google/registry/flows/session/greeting.xml b/core/src/test/resources/google/registry/flows/session/greeting.xml index 4482b7f27..7e303503a 100644 --- a/core/src/test/resources/google/registry/flows/session/greeting.xml +++ b/core/src/test/resources/google/registry/flows/session/greeting.xml @@ -11,9 +11,6 @@ urn:ietf:params:xml:ns:launch-1.0 urn:ietf:params:xml:ns:rgp-1.0 urn:ietf:params:xml:ns:secDNS-1.1 - urn:ietf:params:xml:ns:fee-0.6 - urn:ietf:params:xml:ns:fee-0.11 - urn:ietf:params:xml:ns:fee-0.12 urn:ietf:params:xml:ns:epp:fee-1.0 diff --git a/core/src/test/resources/google/registry/model/domain/domain_check_fee.xml b/core/src/test/resources/google/registry/model/domain/domain_check_fee.xml index f1bf8c569..0a39ab543 100644 --- a/core/src/test/resources/google/registry/model/domain/domain_check_fee.xml +++ b/core/src/test/resources/google/registry/model/domain/domain_check_fee.xml @@ -4,36 +4,15 @@ example.com - example.net - example.org - - example.com - USD - create + xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0"> + USD + 1 - - - example.net - EUR - - create - 2 - - - example.org - EUR - transfer - - - example.xyz - restore - 1 - + ABC-12345 diff --git a/core/src/test/resources/google/registry/model/domain/domain_create_fee.xml b/core/src/test/resources/google/registry/model/domain/domain_create_fee.xml index 866cfb47b..ad0a09e5d 100644 --- a/core/src/test/resources/google/registry/model/domain/domain_create_fee.xml +++ b/core/src/test/resources/google/registry/model/domain/domain_create_fee.xml @@ -19,7 +19,7 @@ - + USD 5.00 diff --git a/core/src/test/resources/google/registry/model/domain/domain_info_fee.xml b/core/src/test/resources/google/registry/model/domain/domain_info_fee.xml deleted file mode 100644 index 26ef413f0..000000000 --- a/core/src/test/resources/google/registry/model/domain/domain_info_fee.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - example.com - - - - - USD - create - 1 - - - ABC-12345 - - diff --git a/core/src/test/resources/google/registry/model/domain/domain_renew_fee.xml b/core/src/test/resources/google/registry/model/domain/domain_renew_fee.xml index fd0dc3834..5178d4a91 100644 --- a/core/src/test/resources/google/registry/model/domain/domain_renew_fee.xml +++ b/core/src/test/resources/google/registry/model/domain/domain_renew_fee.xml @@ -10,7 +10,7 @@ - + USD 5.00 diff --git a/core/src/test/resources/google/registry/model/domain/domain_transfer_request_fee.xml b/core/src/test/resources/google/registry/model/domain/domain_transfer_request_fee.xml index e5f7f8d73..964897120 100644 --- a/core/src/test/resources/google/registry/model/domain/domain_transfer_request_fee.xml +++ b/core/src/test/resources/google/registry/model/domain/domain_transfer_request_fee.xml @@ -11,7 +11,7 @@ - + USD 5.00 8.00 diff --git a/core/src/test/resources/google/registry/model/domain/domain_update_fee.xml b/core/src/test/resources/google/registry/model/domain/domain_update_fee.xml deleted file mode 100644 index 14fb3ed51..000000000 --- a/core/src/test/resources/google/registry/model/domain/domain_update_fee.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - example.com - - - ns2.example.com - - mak21 - - - - - ns1.example.com - - sh8013 - - - - sh8013 - - 2BARfoo - - - - - - - USD - 5.00 - - - ABC-12345 - - diff --git a/core/src/test/resources/google/registry/model/domain_create_anchor_tenant_fee_standard.xml b/core/src/test/resources/google/registry/model/domain_create_anchor_tenant_fee_standard.xml index 08030ce7f..0af3f6d45 100644 --- a/core/src/test/resources/google/registry/model/domain_create_anchor_tenant_fee_standard.xml +++ b/core/src/test/resources/google/registry/model/domain_create_anchor_tenant_fee_standard.xml @@ -19,7 +19,7 @@ false true - + USD 26.00 diff --git a/prober/src/main/resources/google/registry/monitoring/blackbox/message/delete.xml b/prober/src/main/resources/google/registry/monitoring/blackbox/message/delete.xml index 8c8d1cc9e..d23c86344 100644 --- a/prober/src/main/resources/google/registry/monitoring/blackbox/message/delete.xml +++ b/prober/src/main/resources/google/registry/monitoring/blackbox/message/delete.xml @@ -8,4 +8,4 @@ @@CLTRID@@ - \ No newline at end of file + diff --git a/prober/src/main/resources/google/registry/monitoring/blackbox/message/greeting.xml b/prober/src/main/resources/google/registry/monitoring/blackbox/message/greeting.xml index 45d67c656..b87890c14 100644 --- a/prober/src/main/resources/google/registry/monitoring/blackbox/message/greeting.xml +++ b/prober/src/main/resources/google/registry/monitoring/blackbox/message/greeting.xml @@ -17,4 +17,4 @@ - \ No newline at end of file +