Use a potential discount in the AllocationToken when determining domain create price

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=245458027
This commit is contained in:
gbrodman 2019-04-26 11:38:31 -07:00 committed by jianglai
parent 1a1ff94bc5
commit 70c7e6c224
14 changed files with 388 additions and 96 deletions

View file

@ -15,6 +15,7 @@
package google.registry.flows.domain;
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.registry.Registry.TldState.PREDELEGATION;
import static google.registry.model.registry.Registry.TldState.START_DATE_SUNRISE;
@ -63,6 +64,7 @@ import google.registry.flows.domain.DomainFlowUtils.UnknownFeeCommandException;
import google.registry.flows.exceptions.TooManyResourceChecksException;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.registry.label.ReservedList;
@ -182,6 +184,24 @@ public class DomainCheckFlowTest
create(false, "premiumcollision.tld", "Cannot be delegated"));
}
@Test
public void testSuccess_allocationTokenPromotion() throws Exception {
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(UNLIMITED_USE)
.setDiscountFraction(0.5)
.setTokenStatusTransitions(
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
.put(START_OF_TIME, TokenStatus.NOT_STARTED)
.put(clock.nowUtc().plusMillis(1), TokenStatus.VALID)
.put(clock.nowUtc().plusSeconds(1), TokenStatus.ENDED)
.build())
.build());
setEppInput("domain_check_allocationtoken_fee.xml");
runFlowAssertResponse(loadFile("domain_check_allocationtoken_fee_response.xml"));
}
@Test
public void testSuccess_oneReservedInSunrise() throws Exception {
createTld("tld", START_DATE_SUNRISE);

View file

@ -65,6 +65,7 @@ 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 com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig;
import google.registry.flows.EppException;
@ -140,6 +141,8 @@ import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
import google.registry.model.domain.token.AllocationToken.TokenType;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
@ -151,6 +154,7 @@ import google.registry.model.reporting.DomainTransactionRecord.TransactionReport
import google.registry.model.reporting.HistoryEntry;
import google.registry.monitoring.whitebox.EppMetric;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
import java.math.BigDecimal;
import java.util.Map;
import javax.annotation.Nullable;
import org.joda.money.Money;
@ -1101,6 +1105,57 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow,
.isEqualTo(Key.create(getHistoryEntries(reloadResourceByForeignKey()).get(0)));
}
@Test
public void testSuccess_allocationTokenPromotion() throws Exception {
// A discount of 0.5 means that the first-year cost (13) is cut in half, so a discount of 6.5
// Note: we're asking to register it for two years so the total cost should be 13 + (13/2)
persistContactsAndHosts();
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(TokenType.UNLIMITED_USE)
.setDiscountFraction(0.5)
.setTokenStatusTransitions(
ImmutableSortedMap.<DateTime, TokenStatus>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_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld"));
runFlowAssertResponse(
loadFile("domain_create_response.xml", ImmutableMap.of("DOMAIN", "example.tld")));
BillingEvent.OneTime billingEvent =
Iterables.getOnlyElement(ofy().load().type(BillingEvent.OneTime.class));
assertThat(billingEvent.getTargetId()).isEqualTo("example.tld");
assertThat(billingEvent.getCost()).isEqualTo(Money.of(USD, BigDecimal.valueOf(19.5)));
}
@Test
public void testSuccess_promotionDoesNotApplyToPremiumPrice() {
// At the moment, discounts cannot apply to premium domains
createTld("example");
persistContactsAndHosts();
persistResource(
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(TokenType.UNLIMITED_USE)
.setDiscountFraction(0.5)
.setTokenStatusTransitions(
ImmutableSortedMap.<DateTime, TokenStatus>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");
assertThat(assertThrows(IllegalArgumentException.class, this::runFlow))
.hasMessageThat()
.isEqualTo("A nonzero discount code cannot be applied to premium domains");
}
@Test
public void testSuccess_superuserReserved() throws Exception {
setEppInput("domain_create_reserved.xml");

View file

@ -0,0 +1,41 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<check>
<domain:check
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example1.tld</domain:name>
<domain:name>example2.tld</domain:name>
<domain:name>reserved.tld</domain:name>
</domain:check>
</check>
<extension>
<allocationToken:allocationToken
xmlns:allocationToken=
"urn:ietf:params:xml:ns:allocationToken-1.0">
abc123
</allocationToken:allocationToken>
<fee:check
xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
<fee:domain>
<fee:name>example1.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>create</fee:command>
<fee:period unit="y">1</fee:period>
</fee:domain>
<fee:domain>
<fee:name>example2.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>create</fee:command>
<fee:period unit="y">1</fee:period>
</fee:domain>
<fee:domain>
<fee:name>reserved.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>create</fee:command>
<fee:period unit="y">1</fee:period>
</fee:domain>
</fee:check>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1" xmlns:host="urn:ietf:params:xml:ns:host-1.0" xmlns:fee11="urn:ietf:params:xml:ns:fee-0.11" xmlns:fee12="urn:ietf:params:xml:ns:fee-0.12" xmlns:fee="urn:ietf:params:xml:ns:fee-0.6" xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0" xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:chkData>
<domain:cd>
<domain:name avail="true">example1.tld</domain:name>
</domain:cd>
<domain:cd>
<domain:name avail="true">example2.tld</domain:name>
</domain:cd>
<domain:cd>
<domain:name avail="false">reserved.tld</domain:name>
<domain:reason>Reserved</domain:reason>
</domain:cd>
</domain:chkData>
</resData>
<extension>
<fee:chkData>
<fee:cd>
<fee:name>example2.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>create</fee:command>
<fee:period unit="y">1</fee:period>
<fee:fee description="create">6.50</fee:fee>
</fee:cd>
<fee:cd>
<fee:name>example1.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>create</fee:command>
<fee:period unit="y">1</fee:period>
<fee:fee description="create">6.50</fee:fee>
</fee:cd>
<fee:cd>
<fee:name>reserved.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>create</fee:command>
<fee:period unit="y">1</fee:period>
<fee:class>reserved</fee:class>
</fee:cd>
</fee:chkData>
</extension>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,33 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>rich.example</domain:name>
<domain:period unit="y">2</domain:period>
<domain:ns>
<domain:hostObj>ns1.example.net</domain:hostObj>
<domain:hostObj>ns2.example.net</domain:hostObj>
</domain:ns>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<extension>
<allocationToken:allocationToken
xmlns:allocationToken=
"urn:ietf:params:xml:ns:allocationToken-1.0">
abc123
</allocationToken:allocationToken>
<fee:create xmlns:fee="urn:ietf:params:xml:ns:fee-0.12">
<fee:currency>USD</fee:currency>
<fee:fee>193.5</fee:fee>
</fee:create>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -36,7 +36,7 @@ import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry;
import google.registry.testing.AppEngineRule;
import google.registry.testing.ShardableTestCase;
import java.util.Map;
import java.util.function.Function;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
@ -63,7 +63,7 @@ public class AllocationTokenFlowUtilsTest extends ShardableTestCase {
AllocationTokenFlowUtils flowUtils =
new AllocationTokenFlowUtils(new AllocationTokenCustomLogic());
assertThat(
flowUtils.verifyToken(
flowUtils.loadAndVerifyToken(
createCommand("blah.tld"),
"tokeN",
Registry.get("tld"),
@ -80,7 +80,7 @@ public class AllocationTokenFlowUtilsTest extends ShardableTestCase {
assertThrows(
InvalidAllocationTokenException.class,
() ->
flowUtils.verifyToken(
flowUtils.loadAndVerifyToken(
createCommand("blah.tld"),
"tokeN",
Registry.get("tld"),
@ -99,7 +99,7 @@ public class AllocationTokenFlowUtilsTest extends ShardableTestCase {
assertThrows(
IllegalStateException.class,
() ->
flowUtils.verifyToken(
flowUtils.loadAndVerifyToken(
createCommand("blah.tld"),
"tokeN",
Registry.get("tld"),
@ -115,12 +115,14 @@ public class AllocationTokenFlowUtilsTest extends ShardableTestCase {
AllocationTokenFlowUtils flowUtils =
new AllocationTokenFlowUtils(new AllocationTokenCustomLogic());
assertThat(
flowUtils.checkDomainsWithToken(
ImmutableList.of(
InternetDomainName.from("blah.tld"), InternetDomainName.from("blah2.tld")),
"tokeN",
"TheRegistrar",
DateTime.now(UTC)))
flowUtils
.checkDomainsWithToken(
ImmutableList.of(
InternetDomainName.from("blah.tld"), InternetDomainName.from("blah2.tld")),
"tokeN",
"TheRegistrar",
DateTime.now(UTC))
.domainCheckResults())
.containsExactlyEntriesIn(
ImmutableMap.of(
InternetDomainName.from("blah.tld"), "", InternetDomainName.from("blah2.tld"), ""))
@ -138,12 +140,14 @@ public class AllocationTokenFlowUtilsTest extends ShardableTestCase {
AllocationTokenFlowUtils flowUtils =
new AllocationTokenFlowUtils(new AllocationTokenCustomLogic());
assertThat(
flowUtils.checkDomainsWithToken(
ImmutableList.of(
InternetDomainName.from("blah.tld"), InternetDomainName.from("blah2.tld")),
"tokeN",
"TheRegistrar",
DateTime.now(UTC)))
flowUtils
.checkDomainsWithToken(
ImmutableList.of(
InternetDomainName.from("blah.tld"), InternetDomainName.from("blah2.tld")),
"tokeN",
"TheRegistrar",
DateTime.now(UTC))
.domainCheckResults())
.containsExactlyEntriesIn(
ImmutableMap.of(
InternetDomainName.from("blah.tld"),
@ -179,12 +183,14 @@ public class AllocationTokenFlowUtilsTest extends ShardableTestCase {
AllocationTokenFlowUtils flowUtils =
new AllocationTokenFlowUtils(new CustomResultAllocationTokenCustomLogic());
assertThat(
flowUtils.checkDomainsWithToken(
ImmutableList.of(
InternetDomainName.from("blah.tld"), InternetDomainName.from("bunny.tld")),
"tokeN",
"TheRegistrar",
DateTime.now(UTC)))
flowUtils
.checkDomainsWithToken(
ImmutableList.of(
InternetDomainName.from("blah.tld"), InternetDomainName.from("bunny.tld")),
"tokeN",
"TheRegistrar",
DateTime.now(UTC))
.domainCheckResults())
.containsExactlyEntriesIn(
ImmutableMap.of(
InternetDomainName.from("blah.tld"),
@ -215,7 +221,7 @@ public class AllocationTokenFlowUtilsTest extends ShardableTestCase {
@Override
public ImmutableMap<InternetDomainName, String> checkDomainsWithToken(
ImmutableMap<InternetDomainName, String> checkResults,
ImmutableList<InternetDomainName> domainNames,
AllocationToken tokenEntity,
String clientId,
DateTime now) {
@ -228,18 +234,15 @@ public class AllocationTokenFlowUtilsTest extends ShardableTestCase {
@Override
public ImmutableMap<InternetDomainName, String> checkDomainsWithToken(
ImmutableMap<InternetDomainName, String> checkResults,
ImmutableList<InternetDomainName> domainNames,
AllocationToken tokenEntity,
String clientId,
DateTime now) {
return checkResults
.entrySet()
.stream()
return domainNames.stream()
.collect(
ImmutableMap.toImmutableMap(
Map.Entry::getKey,
entry ->
entry.getKey().toString().contains("bunny") ? "fufu" : entry.getValue()));
Function.identity(),
domainName -> domainName.toString().contains("bunny") ? "fufu" : ""));
}
}
}