diff --git a/core/src/main/java/google/registry/model/registry/label/PremiumList.java b/core/src/main/java/google/registry/model/registry/label/PremiumList.java index edc6fe68a..fd53e7e8f 100644 --- a/core/src/main/java/google/registry/model/registry/label/PremiumList.java +++ b/core/src/main/java/google/registry/model/registry/label/PremiumList.java @@ -14,7 +14,9 @@ package google.registry.model.registry.label; +import static com.google.common.base.Charsets.US_ASCII; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.hash.Funnels.stringFunnel; import static com.google.common.hash.Funnels.unencodedCharsFunnel; import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration; import static google.registry.config.RegistryConfig.getSingletonCachePersistDuration; @@ -32,43 +34,82 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader.InvalidCacheLoadException; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.hash.BloomFilter; import com.google.common.util.concurrent.UncheckedExecutionException; import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Id; +import com.googlecode.objectify.annotation.Ignore; import com.googlecode.objectify.annotation.Parent; import google.registry.model.Buildable; import google.registry.model.ImmutableObject; import google.registry.model.annotations.ReportedOn; import google.registry.model.registry.Registry; +import google.registry.schema.replay.DatastoreAndSqlEntity; import google.registry.schema.replay.DatastoreEntity; import google.registry.schema.replay.SqlEntity; +import google.registry.schema.tld.PremiumListDao; import google.registry.util.NonFinalForTesting; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.math.BigDecimal; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; import javax.annotation.Nullable; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; +import javax.persistence.PostLoad; +import javax.persistence.PrePersist; +import javax.persistence.Table; +import javax.persistence.Transient; +import org.hibernate.LazyInitializationException; +import org.joda.money.CurrencyUnit; import org.joda.money.Money; import org.joda.time.Duration; -/** A premium list entity, persisted to Datastore, that is used to check domain label prices. */ +/** + * A premium list entity that is used to check domain label prices. + * + *

Note that the primary key of this entity is {@link #revisionId}, which is auto-generated by + * the database. So, if a retry of insertion happens after the previous attempt unexpectedly + * succeeds, we will end up with having two exact same premium lists that differ only by revisionId. + * This is fine though, because we only use the list with the highest revisionId. + */ @ReportedOn @Entity +@javax.persistence.Entity +@Table(indexes = {@Index(columnList = "name", name = "premiumlist_name_idx")}) public final class PremiumList extends BaseDomainLabelList - implements DatastoreEntity { + implements DatastoreAndSqlEntity { /** Stores the revision key for the set of currently used premium list entry entities. */ - Key revisionKey; + @Transient Key revisionKey; - @Override - public ImmutableList toSqlEntities() { - return ImmutableList.of(); // PremiumList is dual-written - } + @Ignore + @Column(nullable = false) + CurrencyUnit currency; + + @Ignore + @ElementCollection + @CollectionTable( + name = "PremiumEntry", + joinColumns = @JoinColumn(name = "revisionId", referencedColumnName = "revisionId")) + @MapKeyColumn(name = "domainLabel") + @Column(name = "price", nullable = false) + Map labelsToPrices; + + @Ignore + @Column(nullable = false) + BloomFilter bloomFilter; /** Virtual parent entity for premium list entry entities associated with a single revision. */ @ReportedOn @@ -247,6 +288,35 @@ public final class PremiumList extends BaseDomainLabelListNote that this is lazily loaded and thus will throw a {@link LazyInitializationException} if + * used outside the transaction in which the given entity was loaded. You generally should not be + * using this anyway as it's inefficient to load all of the PremiumEntry rows if you don't need + * them. To check prices, use {@link PremiumListDao#getPremiumPrice} instead. + */ + @Nullable + public ImmutableMap getLabelsToPrices() { + return labelsToPrices == null ? null : ImmutableMap.copyOf(labelsToPrices); + } + + /** + * Returns a Bloom filter to determine whether a label might be premium, or is definitely not. + * + *

If the domain label might be premium, then the next step is to check for the existence of a + * corresponding row in the PremiumListEntry table. Otherwise, we know for sure it's not premium, + * and no DB load is required. + */ + public BloomFilter getBloomFilter() { + return bloomFilter; + } + /** * A premium list entry entity, persisted to Datastore. Each instance represents the price of a * single label on a given TLD. @@ -339,9 +409,39 @@ public final class PremiumList extends BaseDomainLabelList labelsToPrices) { + getInstance().labelsToPrices = ImmutableMap.copyOf(labelsToPrices); + return this; + } + @Override public PremiumList build() { + if (getInstance().labelsToPrices != null) { + // ASCII is used for the charset because all premium list domain labels are stored + // punycoded. + getInstance().bloomFilter = + BloomFilter.create(stringFunnel(US_ASCII), getInstance().labelsToPrices.size()); + getInstance() + .labelsToPrices + .keySet() + .forEach(label -> getInstance().bloomFilter.put(label)); + } return super.build(); } } + + @PrePersist + void prePersist() { + lastUpdateTime = creationTime; + } + + @PostLoad + void postLoad() { + creationTime = lastUpdateTime; + } } diff --git a/core/src/main/java/google/registry/schema/tld/PremiumEntry.java b/core/src/main/java/google/registry/schema/tld/PremiumEntry.java index cc5068ff4..ea0ad7c1c 100644 --- a/core/src/main/java/google/registry/schema/tld/PremiumEntry.java +++ b/core/src/main/java/google/registry/schema/tld/PremiumEntry.java @@ -16,6 +16,7 @@ package google.registry.schema.tld; import com.google.common.collect.ImmutableList; import google.registry.model.ImmutableObject; +import google.registry.model.registry.label.PremiumList; import google.registry.schema.replay.DatastoreEntity; import google.registry.schema.replay.SqlEntity; import java.io.Serializable; diff --git a/core/src/main/java/google/registry/schema/tld/PremiumList.java b/core/src/main/java/google/registry/schema/tld/PremiumList.java deleted file mode 100644 index 6b45c5358..000000000 --- a/core/src/main/java/google/registry/schema/tld/PremiumList.java +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2019 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.schema.tld; - -import static com.google.common.base.Charsets.US_ASCII; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.hash.Funnels.stringFunnel; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.hash.BloomFilter; -import google.registry.model.CreateAutoTimestamp; -import google.registry.schema.replay.DatastoreEntity; -import google.registry.schema.replay.SqlEntity; -import java.math.BigDecimal; -import java.util.Map; -import javax.annotation.Nullable; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.MapKeyColumn; -import javax.persistence.Table; -import org.hibernate.LazyInitializationException; -import org.joda.money.CurrencyUnit; -import org.joda.time.DateTime; - -/** - * A list of premium prices for domain names. - * - *

Note that the primary key of this entity is {@link #revisionId}, which is auto-generated by - * the database. So, if a retry of insertion happens after the previous attempt unexpectedly - * succeeds, we will end up with having two exact same premium lists that differ only by revisionId. - * This is fine though, because we only use the list with the highest revisionId. - */ -@Entity -@Table(indexes = {@Index(columnList = "name", name = "premiumlist_name_idx")}) -public class PremiumList implements SqlEntity { - - @Column(nullable = false) - private String name; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(nullable = false) - private Long revisionId; - - @Column(nullable = false) - private CreateAutoTimestamp creationTimestamp = CreateAutoTimestamp.create(null); - - @Column(nullable = false) - private CurrencyUnit currency; - - @ElementCollection - @CollectionTable( - name = "PremiumEntry", - joinColumns = @JoinColumn(name = "revisionId", referencedColumnName = "revisionId")) - @MapKeyColumn(name = "domainLabel") - @Column(name = "price", nullable = false) - private Map labelsToPrices; - - @Column(nullable = false) - private BloomFilter bloomFilter; - - private PremiumList(String name, CurrencyUnit currency, Map labelsToPrices) { - this.name = name; - this.currency = currency; - this.labelsToPrices = labelsToPrices; - // ASCII is used for the charset because all premium list domain labels are stored punycoded. - this.bloomFilter = BloomFilter.create(stringFunnel(US_ASCII), labelsToPrices.size()); - labelsToPrices.keySet().forEach(this.bloomFilter::put); - } - - // Hibernate requires this default constructor. - private PremiumList() {} - - /** Constructs a {@link PremiumList} object. */ - public static PremiumList create( - String name, CurrencyUnit currency, Map labelsToPrices) { - return new PremiumList(name, currency, labelsToPrices); - } - - /** Returns the name of the premium list, which is usually also a TLD string. */ - public String getName() { - return name; - } - - /** Returns the {@link CurrencyUnit} used for this list. */ - public CurrencyUnit getCurrency() { - return currency; - } - - /** Returns the ID of this revision, or throws if null. */ - public Long getRevisionId() { - checkState( - revisionId != null, - "revisionId is null because this object has not yet been persisted to the DB"); - return revisionId; - } - - /** Returns the creation time of this revision of the premium list. */ - public DateTime getCreationTimestamp() { - return creationTimestamp.getTimestamp(); - } - - /** - * Returns a {@link Map} of domain labels to prices. - * - *

Note that this is lazily loaded and thus will throw a {@link LazyInitializationException} if - * used outside the transaction in which the given entity was loaded. You generally should not be - * using this anyway as it's inefficient to load all of the PremiumEntry rows if you don't need - * them. To check prices, use {@link PremiumListDao#getPremiumPrice} instead. - */ - @Nullable - public ImmutableMap getLabelsToPrices() { - return labelsToPrices == null ? null : ImmutableMap.copyOf(labelsToPrices); - } - - /** - * Returns a Bloom filter to determine whether a label might be premium, or is definitely not. - * - *

If the domain label might be premium, then the next step is to check for the existence of a - * corresponding row in the PremiumListEntry table. Otherwise, we know for sure it's not premium, - * and no DB load is required. - */ - public BloomFilter getBloomFilter() { - return bloomFilter; - } - - @Override - public ImmutableList toDatastoreEntities() { - return ImmutableList.of(); // PremiumList is dual-written - } -} diff --git a/core/src/main/java/google/registry/schema/tld/PremiumListCache.java b/core/src/main/java/google/registry/schema/tld/PremiumListCache.java index 2be9565c7..732ba57c7 100644 --- a/core/src/main/java/google/registry/schema/tld/PremiumListCache.java +++ b/core/src/main/java/google/registry/schema/tld/PremiumListCache.java @@ -25,6 +25,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import google.registry.model.registry.label.PremiumList; import google.registry.util.NonFinalForTesting; import java.math.BigDecimal; import java.util.Optional; diff --git a/core/src/main/java/google/registry/schema/tld/PremiumListDao.java b/core/src/main/java/google/registry/schema/tld/PremiumListDao.java index 76830d9f8..e2bec623f 100644 --- a/core/src/main/java/google/registry/schema/tld/PremiumListDao.java +++ b/core/src/main/java/google/registry/schema/tld/PremiumListDao.java @@ -20,6 +20,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory. import com.google.common.cache.CacheLoader.InvalidCacheLoadException; import com.google.common.util.concurrent.UncheckedExecutionException; import google.registry.model.registry.Registry; +import google.registry.model.registry.label.PremiumList; import google.registry.schema.tld.PremiumListCache.RevisionIdAndLabel; import java.math.BigDecimal; import java.util.Optional; diff --git a/core/src/main/java/google/registry/schema/tld/PremiumListUtils.java b/core/src/main/java/google/registry/schema/tld/PremiumListUtils.java index 33fdbf226..c12d77889 100644 --- a/core/src/main/java/google/registry/schema/tld/PremiumListUtils.java +++ b/core/src/main/java/google/registry/schema/tld/PremiumListUtils.java @@ -16,6 +16,7 @@ package google.registry.schema.tld; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static org.joda.time.DateTimeZone.UTC; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableMap; @@ -23,11 +24,13 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; +import google.registry.model.registry.label.PremiumList; import google.registry.model.registry.label.PremiumList.PremiumListEntry; import java.math.BigDecimal; import java.util.List; import java.util.Map; import org.joda.money.CurrencyUnit; +import org.joda.time.DateTime; /** Static utility methods for {@link PremiumList}. */ public class PremiumListUtils { @@ -37,10 +40,7 @@ public class PremiumListUtils { Splitter.on('\n').omitEmptyStrings().splitToList(inputData); ImmutableMap prices = - new google.registry.model.registry.label.PremiumList.Builder() - .setName(name) - .build() - .parse(inputDataPreProcessed); + new PremiumList.Builder().setName(name).build().parse(inputDataPreProcessed); ImmutableSet currencies = prices.values().stream() .map(e -> e.getValue().getCurrencyUnit()) @@ -54,7 +54,12 @@ public class PremiumListUtils { Map priceAmounts = Maps.transformValues(prices, ple -> ple.getValue().getAmount()); - return PremiumList.create(name, currency, priceAmounts); + return new PremiumList.Builder() + .setName(name) + .setCurrency(currency) + .setLabelsToPrices(priceAmounts) + .setCreationTime(DateTime.now(UTC)) + .build(); } private PremiumListUtils() {} diff --git a/core/src/main/java/google/registry/tools/server/CreatePremiumListAction.java b/core/src/main/java/google/registry/tools/server/CreatePremiumListAction.java index 12a17301a..69b5d39b0 100644 --- a/core/src/main/java/google/registry/tools/server/CreatePremiumListAction.java +++ b/core/src/main/java/google/registry/tools/server/CreatePremiumListAction.java @@ -82,7 +82,7 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction { logger.atInfo().log("Saving premium list to Cloud SQL for TLD %s", name); // TODO(mcilwain): Call logInputData() here once Datastore persistence is removed. - google.registry.schema.tld.PremiumList premiumList = parseToPremiumList(name, inputData); + PremiumList premiumList = parseToPremiumList(name, inputData); PremiumListDao.saveNew(premiumList); String message = diff --git a/core/src/main/java/google/registry/tools/server/UpdatePremiumListAction.java b/core/src/main/java/google/registry/tools/server/UpdatePremiumListAction.java index 02dedf441..97d837347 100644 --- a/core/src/main/java/google/registry/tools/server/UpdatePremiumListAction.java +++ b/core/src/main/java/google/registry/tools/server/UpdatePremiumListAction.java @@ -74,7 +74,7 @@ public class UpdatePremiumListAction extends CreateOrUpdatePremiumListAction { protected void saveToCloudSql() { logger.atInfo().log("Updating premium list '%s' in Cloud SQL.", name); // TODO(mcilwain): Add logInputData() call here once DB migration is complete. - google.registry.schema.tld.PremiumList premiumList = parseToPremiumList(name, inputData); + PremiumList premiumList = parseToPremiumList(name, inputData); PremiumListDao.update(premiumList); String message = String.format( diff --git a/core/src/main/resources/META-INF/persistence.xml b/core/src/main/resources/META-INF/persistence.xml index 31d9a59c1..3d8df0bc6 100644 --- a/core/src/main/resources/META-INF/persistence.xml +++ b/core/src/main/resources/META-INF/persistence.xml @@ -29,12 +29,12 @@ google.registry.model.host.HostResource google.registry.model.registrar.Registrar google.registry.model.registrar.RegistrarContact + google.registry.model.registry.label.PremiumList google.registry.model.reporting.Spec11ThreatMatch google.registry.schema.domain.RegistryLock google.registry.schema.tmch.ClaimsList google.registry.schema.cursor.Cursor google.registry.schema.server.Lock - google.registry.schema.tld.PremiumList google.registry.schema.tld.PremiumEntry google.registry.model.domain.secdns.DelegationSignerData google.registry.model.domain.GracePeriod diff --git a/core/src/test/java/google/registry/schema/tld/PremiumListDaoTest.java b/core/src/test/java/google/registry/schema/tld/PremiumListDaoTest.java index 085003372..d8fb3a90f 100644 --- a/core/src/test/java/google/registry/schema/tld/PremiumListDaoTest.java +++ b/core/src/test/java/google/registry/schema/tld/PremiumListDaoTest.java @@ -28,12 +28,14 @@ import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableMap; import com.googlecode.objectify.Key; import google.registry.model.registry.Registry; +import google.registry.model.registry.label.PremiumList; import google.registry.testing.AppEngineRule; import google.registry.testing.FakeClock; import java.math.BigDecimal; import java.util.Optional; import org.joda.money.CurrencyUnit; import org.joda.money.Money; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -51,47 +53,63 @@ public class PremiumListDaoTest { .withClock(fakeClock) .build(); - private static final ImmutableMap TEST_PRICES = - ImmutableMap.of( - "silver", - BigDecimal.valueOf(10.23), - "gold", - BigDecimal.valueOf(1305.47), - "palladium", - BigDecimal.valueOf(1552.78)); + private ImmutableMap testPrices; + + private PremiumList testList; + + @BeforeEach + void setUp() { + testPrices = + ImmutableMap.of( + "silver", + BigDecimal.valueOf(10.23), + "gold", + BigDecimal.valueOf(1305.47), + "palladium", + BigDecimal.valueOf(1552.78)); + testList = + new PremiumList.Builder() + .setName("testname") + .setCurrency(USD) + .setLabelsToPrices(testPrices) + .setCreationTime(fakeClock.nowUtc()) + .build(); + } @Test public void saveNew_worksSuccessfully() { - PremiumList premiumList = PremiumList.create("testname", USD, TEST_PRICES); - PremiumListDao.saveNew(premiumList); + PremiumListDao.saveNew(testList); jpaTm() .transact( () -> { Optional persistedListOpt = PremiumListDao.getLatestRevision("testname"); assertThat(persistedListOpt).isPresent(); PremiumList persistedList = persistedListOpt.get(); - assertThat(persistedList.getLabelsToPrices()).containsExactlyEntriesIn(TEST_PRICES); - assertThat(persistedList.getCreationTimestamp()).isEqualTo(fakeClock.nowUtc()); + assertThat(persistedList.getLabelsToPrices()).containsExactlyEntriesIn(testPrices); + assertThat(persistedList.getCreationTime()).isEqualTo(fakeClock.nowUtc()); }); } @Test public void update_worksSuccessfully() { - PremiumListDao.saveNew(PremiumList.create("testname", CurrencyUnit.USD, TEST_PRICES)); + PremiumListDao.saveNew(testList); Optional persistedList = PremiumListDao.getLatestRevision("testname"); assertThat(persistedList).isPresent(); long firstRevisionId = persistedList.get().getRevisionId(); PremiumListDao.update( - PremiumList.create( - "testname", - CurrencyUnit.USD, - ImmutableMap.of( - "update", - BigDecimal.valueOf(55343.12), - "new", - BigDecimal.valueOf(0.01), - "silver", - BigDecimal.valueOf(30.03)))); + new PremiumList.Builder() + .setName("testname") + .setCurrency(USD) + .setLabelsToPrices( + ImmutableMap.of( + "update", + BigDecimal.valueOf(55343.12), + "new", + BigDecimal.valueOf(0.01), + "silver", + BigDecimal.valueOf(30.03))) + .setCreationTime(fakeClock.nowUtc()) + .build()); jpaTm() .transact( () -> { @@ -107,20 +125,18 @@ public class PremiumListDaoTest { BigDecimal.valueOf(0.01), "silver", BigDecimal.valueOf(30.03))); - assertThat(updatedList.getCreationTimestamp()).isEqualTo(fakeClock.nowUtc()); + assertThat(updatedList.getCreationTime()).isEqualTo(fakeClock.nowUtc()); assertThat(updatedList.getRevisionId()).isGreaterThan(firstRevisionId); - assertThat(updatedList.getCreationTimestamp()).isEqualTo(fakeClock.nowUtc()); + assertThat(updatedList.getCreationTime()).isEqualTo(fakeClock.nowUtc()); }); } @Test public void saveNew_throwsWhenPremiumListAlreadyExists() { - PremiumListDao.saveNew(PremiumList.create("testlist", USD, TEST_PRICES)); + PremiumListDao.saveNew(testList); IllegalArgumentException thrown = - assertThrows( - IllegalArgumentException.class, - () -> PremiumListDao.saveNew(PremiumList.create("testlist", USD, TEST_PRICES))); - assertThat(thrown).hasMessageThat().isEqualTo("Premium list 'testlist' already exists"); + assertThrows(IllegalArgumentException.class, () -> PremiumListDao.saveNew(testList)); + assertThat(thrown).hasMessageThat().isEqualTo("Premium list 'testname' already exists"); } // TODO(b/147246613): Un-ignore this. @@ -128,19 +144,17 @@ public class PremiumListDaoTest { @Disabled public void update_throwsWhenListDoesntExist() { IllegalArgumentException thrown = - assertThrows( - IllegalArgumentException.class, - () -> PremiumListDao.update(PremiumList.create("testlist", USD, TEST_PRICES))); + assertThrows(IllegalArgumentException.class, () -> PremiumListDao.update(testList)); assertThat(thrown) .hasMessageThat() - .isEqualTo("Can't update non-existent premium list 'testlist'"); + .isEqualTo("Can't update non-existent premium list 'testname'"); } @Test public void checkExists_worksSuccessfully() { - assertThat(PremiumListDao.checkExists("testlist")).isFalse(); - PremiumListDao.saveNew(PremiumList.create("testlist", USD, TEST_PRICES)); - assertThat(PremiumListDao.checkExists("testlist")).isTrue(); + assertThat(PremiumListDao.checkExists("testname")).isFalse(); + PremiumListDao.saveNew(testList); + assertThat(PremiumListDao.checkExists("testname")).isTrue(); } @Test @@ -151,8 +165,19 @@ public class PremiumListDaoTest { @Test public void getLatestRevision_worksSuccessfully() { PremiumListDao.saveNew( - PremiumList.create("list1", JPY, ImmutableMap.of("wrong", BigDecimal.valueOf(1000.50)))); - PremiumListDao.update(PremiumList.create("list1", JPY, TEST_PRICES)); + new PremiumList.Builder() + .setName("list1") + .setCurrency(JPY) + .setLabelsToPrices(ImmutableMap.of("wrong", BigDecimal.valueOf(1000.50))) + .setCreationTime(fakeClock.nowUtc()) + .build()); + PremiumListDao.update( + new PremiumList.Builder() + .setName("list1") + .setCurrency(JPY) + .setLabelsToPrices(testPrices) + .setCreationTime(fakeClock.nowUtc()) + .build()); jpaTm() .transact( () -> { @@ -161,7 +186,7 @@ public class PremiumListDaoTest { assertThat(persistedList.get().getName()).isEqualTo("list1"); assertThat(persistedList.get().getCurrency()).isEqualTo(JPY); assertThat(persistedList.get().getLabelsToPrices()) - .containsExactlyEntriesIn(TEST_PRICES); + .containsExactlyEntriesIn(testPrices); }); } @@ -182,7 +207,13 @@ public class PremiumListDaoTest { google.registry.model.registry.label.PremiumList.class, "premlist")) .build()); - PremiumListDao.saveNew(PremiumList.create("premlist", USD, TEST_PRICES)); + PremiumListDao.saveNew( + new PremiumList.Builder() + .setName("premlist") + .setCurrency(USD) + .setLabelsToPrices(testPrices) + .setCreationTime(fakeClock.nowUtc()) + .build()); assertThat(PremiumListDao.getPremiumPrice("silver", Registry.get("foobar"))) .hasValue(Money.of(USD, 10.23)); assertThat(PremiumListDao.getPremiumPrice("gold", Registry.get("foobar"))) @@ -212,16 +243,19 @@ public class PremiumListDaoTest { "premlist")) .build()); PremiumListDao.saveNew( - PremiumList.create( - "premlist", - JPY, - ImmutableMap.of( - "silver", - BigDecimal.valueOf(10.00), - "gold", - BigDecimal.valueOf(1000.0), - "palladium", - BigDecimal.valueOf(15000)))); + new PremiumList.Builder() + .setName("premlist") + .setCurrency(JPY) + .setLabelsToPrices( + ImmutableMap.of( + "silver", + BigDecimal.valueOf(10.00), + "gold", + BigDecimal.valueOf(1000.0), + "palladium", + BigDecimal.valueOf(15000))) + .setCreationTime(fakeClock.nowUtc()) + .build()); assertThat(PremiumListDao.getPremiumPrice("silver", Registry.get("foobar"))) .hasValue(moneyOf(JPY, 10)); assertThat(PremiumListDao.getPremiumPrice("gold", Registry.get("foobar"))) diff --git a/core/src/test/java/google/registry/schema/tld/PremiumListTest.java b/core/src/test/java/google/registry/schema/tld/PremiumListTest.java index 831718d3a..ad9ec32c8 100644 --- a/core/src/test/java/google/registry/schema/tld/PremiumListTest.java +++ b/core/src/test/java/google/registry/schema/tld/PremiumListTest.java @@ -19,16 +19,19 @@ import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.hash.BloomFilter; +import google.registry.model.registry.label.PremiumList; +import google.registry.testing.DatastoreEntityExtension; import java.math.BigDecimal; import org.joda.money.CurrencyUnit; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; /** Unit tests for {@link PremiumList}. */ -@RunWith(JUnit4.class) public class PremiumListTest { + @RegisterExtension + public DatastoreEntityExtension datastoreEntityExtension = new DatastoreEntityExtension(); + private static final ImmutableMap TEST_PRICES = ImmutableMap.of( "silver", @@ -41,7 +44,12 @@ public class PremiumListTest { @Test public void bloomFilter_worksCorrectly() { BloomFilter bloomFilter = - PremiumList.create("testname", CurrencyUnit.USD, TEST_PRICES).getBloomFilter(); + new PremiumList.Builder() + .setName("testname") + .setCurrency(CurrencyUnit.USD) + .setLabelsToPrices(TEST_PRICES) + .build() + .getBloomFilter(); ImmutableSet.of("silver", "gold", "palladium") .forEach(l -> assertThat(bloomFilter.mightContain(l)).isTrue()); ImmutableSet.of("dirt", "pyrite", "zirconia") diff --git a/core/src/test/java/google/registry/schema/tld/PremiumListUtilsTest.java b/core/src/test/java/google/registry/schema/tld/PremiumListUtilsTest.java index 6bc179d6d..419d9aff2 100644 --- a/core/src/test/java/google/registry/schema/tld/PremiumListUtilsTest.java +++ b/core/src/test/java/google/registry/schema/tld/PremiumListUtilsTest.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList; import static org.junit.Assert.assertThrows; +import google.registry.model.registry.label.PremiumList; import google.registry.testing.AppEngineRule; import java.math.BigDecimal; import org.junit.Rule; diff --git a/core/src/test/java/google/registry/tools/server/UpdatePremiumListActionTest.java b/core/src/test/java/google/registry/tools/server/UpdatePremiumListActionTest.java index 8e2915dca..be420b5ba 100644 --- a/core/src/test/java/google/registry/tools/server/UpdatePremiumListActionTest.java +++ b/core/src/test/java/google/registry/tools/server/UpdatePremiumListActionTest.java @@ -94,8 +94,7 @@ public class UpdatePremiumListActionTest { jpaTm() .transact( () -> { - google.registry.schema.tld.PremiumList persistedList = - PremiumListDao.getLatestRevision("foo").get(); + PremiumList persistedList = PremiumListDao.getLatestRevision("foo").get(); assertThat(persistedList.getLabelsToPrices()) .containsEntry("rich", new BigDecimal("75.00")); assertThat(persistedList.getLabelsToPrices()) diff --git a/db/src/main/resources/sql/schema/db-schema.sql.generated b/db/src/main/resources/sql/schema/db-schema.sql.generated index 737f97473..d968f1daf 100644 --- a/db/src/main/resources/sql/schema/db-schema.sql.generated +++ b/db/src/main/resources/sql/schema/db-schema.sql.generated @@ -374,10 +374,10 @@ create sequence history_id_sequence start 1 increment 1; create table "PremiumList" ( revision_id bigserial not null, - bloom_filter bytea not null, creation_timestamp timestamptz not null, - currency text not null, name text not null, + bloom_filter bytea not null, + currency text not null, primary key (revision_id) );