From cfee7e7fd5b7c61175cebc49e7f1e1cd095bf88d Mon Sep 17 00:00:00 2001 From: gbrodman Date: Fri, 12 Apr 2019 08:05:56 -0700 Subject: [PATCH] Add necessary fields to the AllocationToken schema See https://docs.google.com/document/d/1SSWrILRpx0Mtr4sdvlYwz9I8wJp5Gu_o4qlml3iJDKI This is just the base for now--we don't actually do anything with it. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=243265164 --- .../model/domain/token/AllocationToken.java | 171 +++++++++++++++++- .../registry/model/registry/Registry.java | 5 +- .../GenerateAllocationTokensCommand.java | 3 + .../flows/domain/DomainCheckFlowTest.java | 11 +- .../flows/domain/DomainCreateFlowTest.java | 19 +- .../token/AllocationTokenFlowUtilsTest.java | 17 +- .../domain/token/AllocationTokenTest.java | 101 ++++++++++- .../google/registry/model/testdata/schema.txt | 19 ++ .../DeleteAllocationTokensCommandTest.java | 6 +- .../GenerateAllocationTokensCommandTest.java | 10 +- .../tools/GetAllocationTokenCommandTest.java | 25 ++- 11 files changed, 356 insertions(+), 31 deletions(-) diff --git a/java/google/registry/model/domain/token/AllocationToken.java b/java/google/registry/model/domain/token/AllocationToken.java index cc82cb6fb..7352b3f46 100644 --- a/java/google/registry/model/domain/token/AllocationToken.java +++ b/java/google/registry/model/domain/token/AllocationToken.java @@ -16,19 +16,36 @@ package google.registry.model.domain.token; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import static google.registry.model.domain.token.AllocationToken.TokenStatus.CANCELLED; +import static google.registry.model.domain.token.AllocationToken.TokenStatus.ENDED; +import static google.registry.model.domain.token.AllocationToken.TokenStatus.NOT_STARTED; +import static google.registry.model.domain.token.AllocationToken.TokenStatus.VALID; +import static google.registry.util.CollectionUtils.forceEmptyToNull; +import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedMap; import com.googlecode.objectify.Key; +import com.googlecode.objectify.annotation.Embed; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Id; import com.googlecode.objectify.annotation.Index; +import com.googlecode.objectify.annotation.Mapify; +import com.googlecode.objectify.annotation.OnLoad; import google.registry.model.BackupGroupRoot; import google.registry.model.Buildable; import google.registry.model.CreateAutoTimestamp; import google.registry.model.annotations.ReportedOn; +import google.registry.model.common.TimedTransitionProperty; +import google.registry.model.common.TimedTransitionProperty.TimeMapper; +import google.registry.model.common.TimedTransitionProperty.TimedTransition; import google.registry.model.reporting.HistoryEntry; import java.util.Optional; +import java.util.Set; import javax.annotation.Nullable; import org.joda.time.DateTime; @@ -37,6 +54,31 @@ import org.joda.time.DateTime; @Entity public class AllocationToken extends BackupGroupRoot implements Buildable { + // Promotions should only move forward, and ENDED / CANCELLED are terminal states. + private static final ImmutableMultimap VALID_TOKEN_STATUS_TRANSITIONS = + ImmutableMultimap.builder() + .putAll(NOT_STARTED, VALID, CANCELLED) + .putAll(VALID, ENDED, CANCELLED) + .build(); + + /** Single-use tokens are invalid after use. Infinite-use tokens, predictably, are not. */ + public enum TokenType { + SINGLE_USE, + UNLIMITED_USE + } + + /** The status of this token with regards to any potential promotion. */ + public enum TokenStatus { + /** Default status for a token. Either a promotion doesn't exist or it hasn't started. */ + NOT_STARTED, + /** A promotion is currently running. */ + VALID, + /** The promotion has ended. */ + ENDED, + /** The promotion was manually invalidated. */ + CANCELLED + } + /** The allocation token string. */ @Id String token; @@ -49,6 +91,61 @@ public class AllocationToken extends BackupGroupRoot implements Buildable { /** When this token was created. */ CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null); + /** Allowed registrar client IDs for this token, or null if all registrars are allowed. */ + @Nullable Set allowedClientIds; + + /** Allowed TLDs for this token, or null if all TLDs are allowed. */ + @Nullable Set allowedTlds; + + /** + * For promotions, a discount off the base price for the first year between 0.0 and 1.0. + * + *

e.g. a value of 0.15 will mean a 15% discount off the base price for the first year. + */ + double discountFraction; + + /** The type of the token, either single-use or unlimited-use. */ + // TODO(b/130301183): this should not be nullable, we can remove this once we're sure it isn't + @Nullable TokenType tokenType; + + /** + * Promotional token validity periods. + * + *

If the token is promotional, the status will be VALID at the start of the promotion and + * ENDED at the end. If manually cancelled, we will add a CANCELLED status. + */ + @Mapify(TimeMapper.class) + TimedTransitionProperty tokenStatusTransitions = + TimedTransitionProperty.forMapify(NOT_STARTED, TokenStatusTransition.class); + + // TODO(b/130301183): Remove this after loading/saving all token entities + @OnLoad + void onLoad() { + if (tokenType == null) { + tokenType = TokenType.SINGLE_USE; + } + } + + /** + * A transition to a given token status at a specific time, for use in a TimedTransitionProperty. + * + *

Public because App Engine's security manager requires this for instantiation via reflection. + */ + @Embed + public static class TokenStatusTransition extends TimedTransition { + private TokenStatus tokenStatus; + + @Override + public TokenStatus getValue() { + return tokenStatus; + } + + @Override + protected void setValue(TokenStatus tokenStatus) { + this.tokenStatus = tokenStatus; + } + } + public String getToken() { return token; } @@ -69,6 +166,22 @@ public class AllocationToken extends BackupGroupRoot implements Buildable { return Optional.ofNullable(creationTime.getTimestamp()); } + public ImmutableSet getAllowedClientIds() { + return nullToEmptyImmutableCopy(allowedClientIds); + } + + public ImmutableSet getAllowedTlds() { + return nullToEmptyImmutableCopy(allowedTlds); + } + + public double getDiscountFraction() { + return discountFraction; + } + + public TokenType getTokenType() { + return tokenType; + } + @Override public Builder asBuilder() { return new Builder(clone(this)); @@ -82,17 +195,31 @@ public class AllocationToken extends BackupGroupRoot implements Buildable { super(instance); } + @Override + public AllocationToken build() { + checkArgumentNotNull(getInstance().tokenType, "Token type must be specified"); + checkArgument(!Strings.isNullOrEmpty(getInstance().token), "Token must not be null or empty"); + checkArgument( + getInstance().domainName == null || TokenType.SINGLE_USE.equals(getInstance().tokenType), + "Domain name can only be specified for SINGLE_USE tokens"); + checkArgument( + getInstance().redemptionHistoryEntry == null + || TokenType.SINGLE_USE.equals(getInstance().tokenType), + "Redemption history entry can only be specified for SINGLE_USE tokens"); + return super.build(); + } + public Builder setToken(String token) { - checkState(getInstance().token == null, "token can only be set once"); - checkArgumentNotNull(token, "token must not be null"); - checkArgument(!token.isEmpty(), "token must not be blank"); + checkState(getInstance().token == null, "Token can only be set once"); + checkArgumentNotNull(token, "Token must not be null"); + checkArgument(!token.isEmpty(), "Token must not be blank"); getInstance().token = token; return this; } public Builder setRedemptionHistoryEntry(Key redemptionHistoryEntry) { getInstance().redemptionHistoryEntry = - checkArgumentNotNull(redemptionHistoryEntry, "redemptionHistoryEntry must not be null"); + checkArgumentNotNull(redemptionHistoryEntry, "Redemption history entry must not be null"); return this; } @@ -104,9 +231,43 @@ public class AllocationToken extends BackupGroupRoot implements Buildable { @VisibleForTesting public Builder setCreationTimeForTest(DateTime creationTime) { checkState( - getInstance().creationTime.getTimestamp() == null, "creationTime can only be set once"); + getInstance().creationTime.getTimestamp() == null, "Creation time can only be set once"); getInstance().creationTime = CreateAutoTimestamp.create(creationTime); return this; } + + public Builder setAllowedClientIds(Set allowedClientIds) { + getInstance().allowedClientIds = forceEmptyToNull(allowedClientIds); + return this; + } + + public Builder setAllowedTlds(Set allowedTlds) { + getInstance().allowedTlds = forceEmptyToNull(allowedTlds); + return this; + } + + public Builder setDiscountFraction(double discountFraction) { + getInstance().discountFraction = discountFraction; + return this; + } + + public Builder setTokenType(TokenType tokenType) { + checkState(getInstance().tokenType == null, "Token type can only be set once"); + getInstance().tokenType = tokenType; + return this; + } + + public Builder setTokenStatusTransitions( + ImmutableSortedMap transitions) { + getInstance().tokenStatusTransitions = + TimedTransitionProperty.make( + transitions, + TokenStatusTransition.class, + VALID_TOKEN_STATUS_TRANSITIONS, + "", + NOT_STARTED, + ""); + return this; + } } } diff --git a/java/google/registry/model/registry/Registry.java b/java/google/registry/model/registry/Registry.java index 142bfd24c..0bdcd118a 100644 --- a/java/google/registry/model/registry/Registry.java +++ b/java/google/registry/model/registry/Registry.java @@ -154,7 +154,7 @@ public class Registry extends ImmutableObject implements Buildable { /** * A transition to a TLD state at a specific time, for use in a TimedTransitionProperty. Public - * because AppEngine's security manager requires this for instantiation via reflection. + * because App Engine's security manager requires this for instantiation via reflection. */ @Embed public static class TldStateTransition extends TimedTransition { @@ -174,7 +174,8 @@ public class Registry extends ImmutableObject implements Buildable { /** * A transition to a given billing cost at a specific time, for use in a TimedTransitionProperty. - * Public because AppEngine's security manager requires this for instantiation via reflection. + * + *

Public because App Engine's security manager requires this for instantiation via reflection. */ @Embed public static class BillingCostTransition extends TimedTransition { diff --git a/java/google/registry/tools/GenerateAllocationTokensCommand.java b/java/google/registry/tools/GenerateAllocationTokensCommand.java index 773a56352..3e56852f6 100644 --- a/java/google/registry/tools/GenerateAllocationTokensCommand.java +++ b/java/google/registry/tools/GenerateAllocationTokensCommand.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.Queues.newArrayDeque; import static com.google.common.collect.Sets.difference; +import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.StringGenerator.DEFAULT_PASSWORD_LENGTH; import static java.nio.charset.StandardCharsets.UTF_8; @@ -117,6 +118,8 @@ class GenerateAllocationTokensCommand implements CommandWithRemoteApi { .map( t -> { AllocationToken.Builder token = new AllocationToken.Builder().setToken(t); + // TODO(b/129471448): allow this to be unlimited-use as well + token.setTokenType(SINGLE_USE); if (domainNames != null) { token.setDomainName(domainNames.removeFirst()); } diff --git a/javatests/google/registry/flows/domain/DomainCheckFlowTest.java b/javatests/google/registry/flows/domain/DomainCheckFlowTest.java index 96872e1af..112d902c3 100644 --- a/javatests/google/registry/flows/domain/DomainCheckFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainCheckFlowTest.java @@ -14,6 +14,7 @@ package google.registry.flows.domain; +import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_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; @@ -83,7 +84,11 @@ public class DomainCheckFlowTest private ReservedList createReservedList() { persistResource( - new AllocationToken.Builder().setDomainName("anchor.tld").setToken("2fooBAR").build()); + new AllocationToken.Builder() + .setDomainName("anchor.tld") + .setToken("2fooBAR") + .setTokenType(SINGLE_USE) + .build()); return persistReservedList( "tld-reserved", "reserved,FULLY_BLOCKED", @@ -140,7 +145,8 @@ public class DomainCheckFlowTest public void testSuccess_oneExists_allocationTokenIsValid() throws Exception { setEppInput("domain_check_allocationtoken.xml"); persistActiveDomain("example1.tld"); - persistResource(new AllocationToken.Builder().setToken("abc123").build()); + persistResource( + new AllocationToken.Builder().setToken("abc123").setTokenType(SINGLE_USE).build()); doCheckTest( create(false, "example1.tld", "In use"), create(true, "example2.tld", null), @@ -154,6 +160,7 @@ public class DomainCheckFlowTest persistResource( new AllocationToken.Builder() .setToken("abc123") + .setTokenType(SINGLE_USE) .setRedemptionHistoryEntry(Key.create(HistoryEntry.class, 1L)) .build()); doCheckTest( diff --git a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java index b8d5a3026..f16beb1dd 100644 --- a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java @@ -21,6 +21,7 @@ import static google.registry.flows.FlowTestCase.UserPrivileges.SUPERUSER; import static google.registry.model.billing.BillingEvent.Flag.ANCHOR_TENANT; import static google.registry.model.billing.BillingEvent.Flag.SUNRISE; import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS; +import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE; import static google.registry.model.eppcommon.StatusValue.OK; import static google.registry.model.eppcommon.StatusValue.PENDING_DELETE; import static google.registry.model.eppcommon.StatusValue.SERVER_HOLD; @@ -175,7 +176,11 @@ public class DomainCreateFlowTest extends ResourceFlowTestCasenaturalOrder() + .put(DateTimeUtils.START_OF_TIME, TokenStatus.NOT_STARTED) + .put(DateTime.now(UTC), TokenStatus.VALID) + .put(DateTime.now(UTC).plusWeeks(8), TokenStatus.ENDED) + .build()) + .build()); + assertThat(ofy().load().entity(unlimitedUseToken).now()).isEqualTo(unlimitedUseToken); + + AllocationToken singleUseToken = persistResource( new AllocationToken.Builder() .setToken("abc123") .setRedemptionHistoryEntry(Key.create(HistoryEntry.class, 1L)) .setDomainName("foo.example") .setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z")) + .setTokenType(SINGLE_USE) .build()); - assertThat(ofy().load().entity(token).now()).isEqualTo(token); + assertThat(ofy().load().entity(singleUseToken).now()).isEqualTo(singleUseToken); } @Test @@ -48,6 +75,7 @@ public class AllocationTokenTest extends EntityTestCase { persistResource( new AllocationToken.Builder() .setToken("abc123") + .setTokenType(SINGLE_USE) .setRedemptionHistoryEntry(Key.create(HistoryEntry.class, 1L)) .setDomainName("blahdomain.fake") .setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z")) @@ -60,7 +88,7 @@ public class AllocationTokenTest extends EntityTestCase { @Test public void testCreationTime_autoPopulates() { AllocationToken tokenBeforePersisting = - new AllocationToken.Builder().setToken("abc123").build(); + new AllocationToken.Builder().setToken("abc123").setTokenType(SINGLE_USE).build(); assertThat(tokenBeforePersisting.getCreationTime()).isEmpty(); AllocationToken tokenAfterPersisting = persistResource(tokenBeforePersisting); assertThat(tokenAfterPersisting.getCreationTime()).hasValue(clock.nowUtc()); @@ -71,12 +99,13 @@ public class AllocationTokenTest extends EntityTestCase { AllocationToken.Builder builder = new AllocationToken.Builder() .setToken("foobar") + .setTokenType(SINGLE_USE) .setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z")); IllegalStateException thrown = assertThrows( IllegalStateException.class, () -> builder.setCreationTimeForTest(DateTime.parse("2010-11-13T05:00:00Z"))); - assertThat(thrown).hasMessageThat().isEqualTo("creationTime can only be set once"); + assertThat(thrown).hasMessageThat().isEqualTo("Creation time can only be set once"); } @Test @@ -84,6 +113,68 @@ public class AllocationTokenTest extends EntityTestCase { AllocationToken.Builder builder = new AllocationToken.Builder().setToken("foobar"); IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> builder.setToken("barfoo")); - assertThat(thrown).hasMessageThat().isEqualTo("token can only be set once"); + assertThat(thrown).hasMessageThat().isEqualTo("Token can only be set once"); + } + + @Test + public void testSetTokenType_cantCallMoreThanOnce() { + AllocationToken.Builder builder = + new AllocationToken.Builder().setTokenType(TokenType.UNLIMITED_USE); + IllegalStateException thrown = + assertThrows(IllegalStateException.class, () -> builder.setTokenType(SINGLE_USE)); + assertThat(thrown).hasMessageThat().isEqualTo("Token type can only be set once"); + } + + @Test + public void testBuild_domainNameOnlyOnSingleUse() { + AllocationToken.Builder builder = + new AllocationToken.Builder() + .setToken("foobar") + .setTokenType(TokenType.UNLIMITED_USE) + .setDomainName("foo.example"); + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, builder::build); + assertThat(thrown) + .hasMessageThat() + .isEqualTo("Domain name can only be specified for SINGLE_USE tokens"); + } + + @Test + public void testBuild_redemptionHistoryEntryOnlyInSingleUse() { + AllocationToken.Builder builder = + new AllocationToken.Builder() + .setToken("foobar") + .setTokenType(TokenType.UNLIMITED_USE) + .setRedemptionHistoryEntry(Key.create(HistoryEntry.class, "hi")); + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, builder::build); + assertThat(thrown) + .hasMessageThat() + .isEqualTo("Redemption history entry can only be specified for SINGLE_USE tokens"); + } + + @Test + public void testBuild_noTokenType() { + IllegalArgumentException thrown = + assertThrows( + IllegalArgumentException.class, + () -> new AllocationToken.Builder().setToken("foobar").build()); + assertThat(thrown).hasMessageThat().isEqualTo("Token type must be specified"); + } + + @Test + public void testBuild_noToken() { + IllegalArgumentException thrown = + assertThrows( + IllegalArgumentException.class, + () -> new AllocationToken.Builder().setTokenType(SINGLE_USE).build()); + assertThat(thrown).hasMessageThat().isEqualTo("Token must not be null or empty"); + } + + @Test + public void testBuild_emptyToken() { + IllegalArgumentException thrown = + assertThrows( + IllegalArgumentException.class, + () -> new AllocationToken.Builder().setToken("").setTokenType(SINGLE_USE).build()); + assertThat(thrown).hasMessageThat().isEqualTo("Token must not be blank"); } } diff --git a/javatests/google/registry/model/testdata/schema.txt b/javatests/google/registry/model/testdata/schema.txt index abede7367..f82e000fc 100644 --- a/javatests/google/registry/model/testdata/schema.txt +++ b/javatests/google/registry/model/testdata/schema.txt @@ -231,9 +231,28 @@ class google.registry.model.domain.secdns.DelegationSignerData { class google.registry.model.domain.token.AllocationToken { @Id java.lang.String token; com.googlecode.objectify.Key redemptionHistoryEntry; + double discountFraction; google.registry.model.CreateAutoTimestamp creationTime; google.registry.model.UpdateAutoTimestamp updateTimestamp; + google.registry.model.common.TimedTransitionProperty tokenStatusTransitions; + google.registry.model.domain.token.AllocationToken$TokenType tokenType; java.lang.String domainName; + java.util.Set allowedClientIds; + java.util.Set allowedTlds; +} +enum google.registry.model.domain.token.AllocationToken$TokenStatus { + CANCELLED; + ENDED; + NOT_STARTED; + VALID; +} +class google.registry.model.domain.token.AllocationToken$TokenStatusTransition { + google.registry.model.domain.token.AllocationToken$TokenStatus tokenStatus; + org.joda.time.DateTime transitionTime; +} +enum google.registry.model.domain.token.AllocationToken$TokenType { + SINGLE_USE; + UNLIMITED_USE; } class google.registry.model.eppcommon.AuthInfo$PasswordAuth { java.lang.String repoId; diff --git a/javatests/google/registry/tools/DeleteAllocationTokensCommandTest.java b/javatests/google/registry/tools/DeleteAllocationTokensCommandTest.java index ed2a71a14..92d723f9d 100644 --- a/javatests/google/registry/tools/DeleteAllocationTokensCommandTest.java +++ b/javatests/google/registry/tools/DeleteAllocationTokensCommandTest.java @@ -15,6 +15,7 @@ package google.registry.tools; import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.testing.DatastoreHelper.persistResource; import static google.registry.testing.JUnitBackports.assertThrows; @@ -129,7 +130,10 @@ public class DeleteAllocationTokensCommandTest private static AllocationToken persistToken( String token, @Nullable String domainName, boolean redeemed) { AllocationToken.Builder builder = - new AllocationToken.Builder().setToken(token).setDomainName(domainName); + new AllocationToken.Builder() + .setToken(token) + .setTokenType(SINGLE_USE) + .setDomainName(domainName); if (redeemed) { builder.setRedemptionHistoryEntry(Key.create(HistoryEntry.class, 1051L)); } diff --git a/javatests/google/registry/tools/GenerateAllocationTokensCommandTest.java b/javatests/google/registry/tools/GenerateAllocationTokensCommandTest.java index 5777a7f14..db4615991 100644 --- a/javatests/google/registry/tools/GenerateAllocationTokensCommandTest.java +++ b/javatests/google/registry/tools/GenerateAllocationTokensCommandTest.java @@ -15,6 +15,7 @@ package google.registry.tools; import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.testing.DatastoreHelper.persistResource; import static google.registry.testing.JUnitBackports.assertThrows; @@ -94,7 +95,11 @@ public class GenerateAllocationTokensCommandTest @Test public void testSuccess_tokenCollision() throws Exception { AllocationToken existingToken = - persistResource(new AllocationToken.Builder().setToken("DEADBEEF123456789ABC").build()); + persistResource( + new AllocationToken.Builder() + .setToken("DEADBEEF123456789ABC") + .setTokenType(SINGLE_USE) + .build()); runCommand("--number", "1", "--prefix", "DEADBEEF", "--length", "12"); assertAllocationTokens(existingToken, createToken("DEADBEEFDEFGHJKLMNPQ", null, null)); assertInStdout("DEADBEEFDEFGHJKLMNPQ"); @@ -177,7 +182,8 @@ public class GenerateAllocationTokensCommandTest String token, @Nullable Key redemptionHistoryEntry, @Nullable String domainName) { - AllocationToken.Builder builder = new AllocationToken.Builder().setToken(token); + AllocationToken.Builder builder = + new AllocationToken.Builder().setToken(token).setTokenType(SINGLE_USE); if (redemptionHistoryEntry != null) { builder.setRedemptionHistoryEntry(redemptionHistoryEntry); } diff --git a/javatests/google/registry/tools/GetAllocationTokenCommandTest.java b/javatests/google/registry/tools/GetAllocationTokenCommandTest.java index 0343b126d..617ff7115 100644 --- a/javatests/google/registry/tools/GetAllocationTokenCommandTest.java +++ b/javatests/google/registry/tools/GetAllocationTokenCommandTest.java @@ -14,6 +14,7 @@ package google.registry.tools; +import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE; import static google.registry.testing.DatastoreHelper.createHistoryEntryForEppResource; import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.persistActiveDomain; @@ -36,7 +37,11 @@ public class GetAllocationTokenCommandTest extends CommandTestCase