Add a registration_behavior column to AllocationToken (#1695)

This is, as of now, unused but we can use it for b/237683906 and
b/237800445 in the future to allow for special behavior dictated by
allocation tokens rather than having to reserve specific domains.

Note that we enforce a tied domain for ANCHOR_TENANT tokens (because
they should be matched to a domain) but not for BYPASS_TLD_STATE tokens.
This commit is contained in:
gbrodman
2022-07-20 12:50:25 -04:00
committed by GitHub
parent 49b1b2d058
commit cf89d9354c
10 changed files with 217 additions and 6 deletions
@@ -36,6 +36,7 @@ import com.googlecode.objectify.Key;
import google.registry.model.EntityTestCase;
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.token.AllocationToken.RegistrationBehavior;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
import google.registry.model.domain.token.AllocationToken.TokenType;
import google.registry.model.reporting.HistoryEntry;
@@ -449,6 +450,34 @@ public class AllocationTokenTest extends EntityTestCase {
.isEqualTo("Discount years can only be specified along with a discount fraction");
}
@Test
void testBuild_registrationBehaviors() {
createTld("tld");
// BYPASS_TLD_STATE doesn't require a domain
AllocationToken token =
new AllocationToken.Builder()
.setToken("abc")
.setTokenType(SINGLE_USE)
.setRegistrationBehavior(RegistrationBehavior.BYPASS_TLD_STATE)
.build();
// ANCHOR_TENANT does
assertThat(
assertThrows(
IllegalArgumentException.class,
() ->
token
.asBuilder()
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.build()))
.hasMessageThat()
.isEqualTo("ANCHOR_TENANT tokens must be tied to a domain");
token
.asBuilder()
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
.setDomainName("example.tld")
.build();
}
private void assertBadInitialTransition(TokenStatus status) {
assertBadTransition(
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
@@ -14,6 +14,7 @@
package google.registry.tools;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.NONPREMIUM;
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.SPECIFIED;
@@ -260,6 +261,64 @@ class GenerateAllocationTokensCommandTest extends CommandTestCase<GenerateAlloca
+ " NONPREMIUM, SPECIFIED]");
}
@Test
void testSuccess_defaultRegistrationBehavior() throws Exception {
runCommand("--tokens", "foobar,blah");
assertThat(
loadAllOf(AllocationToken.class).stream()
.map(AllocationToken::getRegistrationBehavior)
.collect(toImmutableList()))
.containsExactly(
AllocationToken.RegistrationBehavior.DEFAULT,
AllocationToken.RegistrationBehavior.DEFAULT);
}
@Test
void testSuccess_defaultRegistrationBehavior_specified() throws Exception {
runCommand("--tokens", "foobar,blah", "--registration_behavior", "DEFAULT");
assertThat(
loadAllOf(AllocationToken.class).stream()
.map(AllocationToken::getRegistrationBehavior)
.collect(toImmutableList()))
.containsExactly(
AllocationToken.RegistrationBehavior.DEFAULT,
AllocationToken.RegistrationBehavior.DEFAULT);
}
@Test
void testSuccess_specifiedRegistrationBehavior() throws Exception {
runCommand("--tokens", "foobar,blah", "--registration_behavior", "BYPASS_TLD_STATE");
assertThat(
loadAllOf(AllocationToken.class).stream()
.map(AllocationToken::getRegistrationBehavior)
.collect(toImmutableList()))
.containsExactly(
AllocationToken.RegistrationBehavior.BYPASS_TLD_STATE,
AllocationToken.RegistrationBehavior.BYPASS_TLD_STATE);
}
@Test
void testFailure_invalidRegistrationBehaviors() throws Exception {
assertThat(
assertThrows(
ParameterException.class,
() -> runCommand("--tokens", "foobar", "--registration_behavior")))
.hasMessageThat()
.contains("Expected a value after parameter --registration_behavior");
assertThat(
assertThrows(
ParameterException.class,
() -> runCommand("--tokens", "foobar", "--registration_behavior", "bad")))
.hasMessageThat()
.contains("Invalid value for --registration_behavior");
assertThat(
assertThrows(
ParameterException.class,
() -> runCommand("--tokens", "foobar", "--registration_behavior", "")))
.hasMessageThat()
.contains("Invalid value for --registration_behavior");
}
@Test
void testSuccess_specifyManyTokens() throws Exception {
command.stringGenerator =
@@ -24,6 +24,7 @@ import static google.registry.model.domain.token.AllocationToken.TokenStatus.NOT
import static google.registry.model.domain.token.AllocationToken.TokenStatus.VALID;
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.testing.DatabaseHelper.loadByEntity;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.time.DateTimeZone.UTC;
@@ -33,6 +34,7 @@ import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.RegistrationBehavior;
import google.registry.model.domain.token.AllocationToken.TokenStatus;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Test;
@@ -190,6 +192,67 @@ class UpdateAllocationTokensCommandTest extends CommandTestCase<UpdateAllocation
+ " NONPREMIUM, SPECIFIED]");
}
@Test
void testSuccess_registrationBehavior_same() throws Exception {
AllocationToken token =
persistResource(
builderWithPromo()
.setRegistrationBehavior(AllocationToken.RegistrationBehavior.BYPASS_TLD_STATE)
.build());
assertThat(token.getRegistrationBehavior())
.isEqualTo(AllocationToken.RegistrationBehavior.BYPASS_TLD_STATE);
runCommandForced("--tokens", "token", "--registration_behavior", "BYPASS_TLD_STATE");
assertThat(loadByEntity(token).getRegistrationBehavior())
.isEqualTo(AllocationToken.RegistrationBehavior.BYPASS_TLD_STATE);
}
@Test
void testSuccess_registrationBehavior_different() throws Exception {
AllocationToken token = persistResource(builderWithPromo().build());
assertThat(token.getRegistrationBehavior())
.isEqualTo(AllocationToken.RegistrationBehavior.DEFAULT);
runCommandForced("--tokens", "token", "--registration_behavior", "BYPASS_TLD_STATE");
assertThat(loadByEntity(token).getRegistrationBehavior())
.isEqualTo(RegistrationBehavior.BYPASS_TLD_STATE);
}
@Test
void testFailure_registrationBehavior_enforcesAnchorTenantRestriction() throws Exception {
AllocationToken token = persistResource(builderWithPromo().build());
assertThat(token.getRegistrationBehavior())
.isEqualTo(AllocationToken.RegistrationBehavior.DEFAULT);
assertThat(
assertThrows(
IllegalArgumentException.class,
() ->
runCommandForced(
"--tokens", "token", "--registration_behavior", "ANCHOR_TENANT")))
.hasMessageThat()
.isEqualTo("ANCHOR_TENANT tokens must be tied to a domain");
}
@Test
void testFailure_registrationBehavior_invalid() throws Exception {
assertThat(
assertThrows(
ParameterException.class,
() -> runCommand("--tokens", "foobar", "--registration_behavior")))
.hasMessageThat()
.contains("Expected a value after parameter --registration_behavior");
assertThat(
assertThrows(
ParameterException.class,
() -> runCommand("--tokens", "foobar", "--registration_behavior", "bad")))
.hasMessageThat()
.contains("Invalid value for --registration_behavior");
assertThat(
assertThrows(
ParameterException.class,
() -> runCommand("--tokens", "foobar", "--registration_behavior", "")))
.hasMessageThat()
.contains("Invalid value for --registration_behavior");
}
@Test
void testUpdateStatusTransitions() throws Exception {
DateTime now = DateTime.now(UTC);
@@ -338,6 +338,7 @@ class google.registry.model.domain.token.AllocationToken {
google.registry.model.UpdateAutoTimestamp updateTimestamp;
google.registry.model.billing.BillingEvent$RenewalPriceBehavior renewalPriceBehavior;
google.registry.model.common.TimedTransitionProperty<google.registry.model.domain.token.AllocationToken$TokenStatus> tokenStatusTransitions;
google.registry.model.domain.token.AllocationToken$RegistrationBehavior registrationBehavior;
google.registry.model.domain.token.AllocationToken$TokenType tokenType;
google.registry.persistence.DomainHistoryVKey redemptionHistoryEntry;
int discountYears;
@@ -345,6 +346,11 @@ class google.registry.model.domain.token.AllocationToken {
java.util.Set<java.lang.String> allowedClientIds;
java.util.Set<java.lang.String> allowedTlds;
}
enum google.registry.model.domain.token.AllocationToken$RegistrationBehavior {
ANCHOR_TENANT;
BYPASS_TLD_STATE;
DEFAULT;
}
enum google.registry.model.domain.token.AllocationToken$TokenStatus {
CANCELLED;
ENDED;