mirror of
https://github.com/google/nomulus.git
synced 2025-05-19 18:59:35 +02:00
Move premium list static helper methods into their own class
It was kind of messy having all of that logic living alongside the entities themselves. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=148498024
This commit is contained in:
parent
388dd1055e
commit
ea4e471c04
12 changed files with 523 additions and 421 deletions
|
@ -17,7 +17,7 @@ package google.registry.model.pricing;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.base.Strings.emptyToNull;
|
import static com.google.common.base.Strings.emptyToNull;
|
||||||
import static google.registry.model.registry.Registry.TldState.SUNRISE;
|
import static google.registry.model.registry.Registry.TldState.SUNRISE;
|
||||||
import static google.registry.model.registry.label.PremiumList.getPremiumPrice;
|
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
|
||||||
import static google.registry.model.registry.label.ReservationType.NAME_COLLISION;
|
import static google.registry.model.registry.label.ReservationType.NAME_COLLISION;
|
||||||
import static google.registry.model.registry.label.ReservedList.getReservation;
|
import static google.registry.model.registry.label.ReservedList.getReservation;
|
||||||
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
|
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
|
||||||
|
|
|
@ -13,10 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package google.registry.model.registry.label;
|
package google.registry.model.registry.label;
|
||||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
|
||||||
import static com.google.common.collect.Iterables.partition;
|
|
||||||
import static com.google.common.hash.Funnels.unencodedCharsFunnel;
|
import static com.google.common.hash.Funnels.unencodedCharsFunnel;
|
||||||
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
|
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
|
||||||
import static google.registry.config.RegistryConfig.getSingletonCachePersistDuration;
|
import static google.registry.config.RegistryConfig.getSingletonCachePersistDuration;
|
||||||
|
@ -28,20 +25,15 @@ import static google.registry.model.ofy.Ofy.RECOMMENDED_MEMCACHE_EXPIRATION;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
|
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.google.common.collect.FluentIterable;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.hash.BloomFilter;
|
import com.google.common.hash.BloomFilter;
|
||||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.VoidWork;
|
|
||||||
import com.googlecode.objectify.Work;
|
import com.googlecode.objectify.Work;
|
||||||
import com.googlecode.objectify.annotation.Cache;
|
import com.googlecode.objectify.annotation.Cache;
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
import com.googlecode.objectify.annotation.Entity;
|
||||||
|
@ -55,13 +47,11 @@ import google.registry.model.registry.Registry;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import org.joda.money.Money;
|
import org.joda.money.Money;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A premium list entity, persisted to Datastore, that is used to check domain label prices.
|
* A premium list entity, persisted to Datastore, that is used to check domain label prices.
|
||||||
|
@ -71,9 +61,6 @@ import org.joda.time.DateTime;
|
||||||
@Cache(expirationSeconds = RECOMMENDED_MEMCACHE_EXPIRATION)
|
@Cache(expirationSeconds = RECOMMENDED_MEMCACHE_EXPIRATION)
|
||||||
public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.PremiumListEntry> {
|
public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.PremiumListEntry> {
|
||||||
|
|
||||||
/** The number of premium list entry entities that are created and deleted per batch. */
|
|
||||||
private static final int TRANSACTION_BATCH_SIZE = 200;
|
|
||||||
|
|
||||||
/** Stores the revision key for the set of currently used premium list entry entities. */
|
/** Stores the revision key for the set of currently used premium list entry entities. */
|
||||||
Key<PremiumListRevision> revisionKey;
|
Key<PremiumListRevision> revisionKey;
|
||||||
|
|
||||||
|
@ -139,7 +126,7 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||||
* <p>This is cached for a shorter duration because we need to periodically reload this entity to
|
* <p>This is cached for a shorter duration because we need to periodically reload this entity to
|
||||||
* check if a new revision has been published, and if so, then use that.
|
* check if a new revision has been published, and if so, then use that.
|
||||||
*/
|
*/
|
||||||
private static final LoadingCache<String, PremiumList> cachePremiumLists =
|
static final LoadingCache<String, PremiumList> cachePremiumLists =
|
||||||
CacheBuilder.newBuilder()
|
CacheBuilder.newBuilder()
|
||||||
.expireAfterWrite(getDomainLabelListCacheDuration().getMillis(), MILLISECONDS)
|
.expireAfterWrite(getDomainLabelListCacheDuration().getMillis(), MILLISECONDS)
|
||||||
.build(new CacheLoader<String, PremiumList>() {
|
.build(new CacheLoader<String, PremiumList>() {
|
||||||
|
@ -163,7 +150,7 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||||
* {@link PremiumListRevision} is immutable and cannot ever be changed once created, so its cache
|
* {@link PremiumListRevision} is immutable and cannot ever be changed once created, so its cache
|
||||||
* need not ever expire.
|
* need not ever expire.
|
||||||
*/
|
*/
|
||||||
private static final LoadingCache<Key<PremiumListRevision>, PremiumListRevision>
|
static final LoadingCache<Key<PremiumListRevision>, PremiumListRevision>
|
||||||
cachePremiumListRevisions =
|
cachePremiumListRevisions =
|
||||||
CacheBuilder.newBuilder()
|
CacheBuilder.newBuilder()
|
||||||
.expireAfterWrite(getSingletonCachePersistDuration().getMillis(), MILLISECONDS)
|
.expireAfterWrite(getSingletonCachePersistDuration().getMillis(), MILLISECONDS)
|
||||||
|
@ -214,67 +201,6 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||||
}});
|
}});
|
||||||
}});
|
}});
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the premium price for the specified label and registry, or absent if the label is not
|
|
||||||
* premium.
|
|
||||||
*/
|
|
||||||
public static Optional<Money> getPremiumPrice(String label, Registry registry) {
|
|
||||||
// If the registry has no configured premium list, then no labels are premium.
|
|
||||||
if (registry.getPremiumList() == null) {
|
|
||||||
return Optional.<Money> absent();
|
|
||||||
}
|
|
||||||
String listName = registry.getPremiumList().getName();
|
|
||||||
Optional<PremiumList> optionalPremiumList = get(listName);
|
|
||||||
checkState(optionalPremiumList.isPresent(), "Could not load premium list '%s'", listName);
|
|
||||||
PremiumList premiumList = optionalPremiumList.get();
|
|
||||||
PremiumListRevision revision;
|
|
||||||
try {
|
|
||||||
revision = cachePremiumListRevisions.get(premiumList.getRevisionKey());
|
|
||||||
} catch (InvalidCacheLoadException | ExecutionException e) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Could not load premium list revision " + premiumList.getRevisionKey(), e);
|
|
||||||
}
|
|
||||||
checkState(
|
|
||||||
revision.probablePremiumLabels != null,
|
|
||||||
"Probable premium labels bloom filter is null on revision '%s'",
|
|
||||||
premiumList.getRevisionKey());
|
|
||||||
|
|
||||||
if (revision.probablePremiumLabels.mightContain(label)) {
|
|
||||||
Key<PremiumListEntry> entryKey =
|
|
||||||
Key.create(premiumList.getRevisionKey(), PremiumListEntry.class, label);
|
|
||||||
try {
|
|
||||||
Optional<PremiumListEntry> entry = cachePremiumListEntries.get(entryKey);
|
|
||||||
return (entry.isPresent()) ? Optional.of(entry.get().getValue()) : Optional.<Money>absent();
|
|
||||||
} catch (InvalidCacheLoadException | ExecutionException e) {
|
|
||||||
throw new RuntimeException("Could not load premium list entry " + entryKey, e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Optional.<Money>absent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads and returns the entire premium list map.
|
|
||||||
*
|
|
||||||
* <p>This load operation is quite expensive for large premium lists because each premium list
|
|
||||||
* entry is a separate Datastore entity, and loading them this way bypasses the in-memory caches.
|
|
||||||
* Do not use this method if all you need to do is check the price of a small number of labels!
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
public Map<String, PremiumListEntry> loadPremiumListEntries() {
|
|
||||||
try {
|
|
||||||
ImmutableMap.Builder<String, PremiumListEntry> entriesMap = new ImmutableMap.Builder<>();
|
|
||||||
if (revisionKey != null) {
|
|
||||||
for (PremiumListEntry entry : queryEntriesForCurrentRevision()) {
|
|
||||||
entriesMap.put(entry.getLabel(), entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return entriesMap.build();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Could not retrieve entries for premium list " + name, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public Key<PremiumListRevision> getRevisionKey() {
|
public Key<PremiumListRevision> getRevisionKey() {
|
||||||
return revisionKey;
|
return revisionKey;
|
||||||
|
@ -291,11 +217,6 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether a PremiumList of the given name exists, bypassing the cache. */
|
|
||||||
public static boolean exists(String name) {
|
|
||||||
return ofy().load().key(Key.create(getCrossTldKey(), PremiumList.class, name)).now() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A premium list entry entity, persisted to Datastore. Each instance represents the price of a
|
* A premium list entry entity, persisted to Datastore. Each instance represents the price of a
|
||||||
* single label on a given TLD.
|
* single label on a given TLD.
|
||||||
|
@ -361,124 +282,12 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PremiumList saveWithEntries(
|
|
||||||
PremiumList premiumList, Iterable<String> premiumListLines) {
|
|
||||||
return saveWithEntries(premiumList, premiumList.parse(premiumListLines));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Re-parents the given {@link PremiumListEntry}s on the given {@link PremiumListRevision}. */
|
|
||||||
public static ImmutableSet<PremiumListEntry> parentEntriesOnRevision(
|
|
||||||
Iterable<PremiumListEntry> entries, final Key<PremiumListRevision> revisionKey) {
|
|
||||||
return FluentIterable.from(firstNonNull(entries, ImmutableSet.of()))
|
|
||||||
.transform(
|
|
||||||
new Function<PremiumListEntry, PremiumListEntry>() {
|
|
||||||
@Override
|
|
||||||
public PremiumListEntry apply(PremiumListEntry entry) {
|
|
||||||
return entry.asBuilder().setParent(revisionKey).build();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.toSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persists a new or updated PremiumList object and its descendant entities to Datastore.
|
|
||||||
*
|
|
||||||
* <p>The flow here is: save the new premium list entries parented on that revision entity,
|
|
||||||
* save/update the PremiumList, and then delete the old premium list entries associated with the
|
|
||||||
* old revision.
|
|
||||||
*
|
|
||||||
* <p>This is the only valid way to save these kinds of entities!
|
|
||||||
*/
|
|
||||||
public static PremiumList saveWithEntries(
|
|
||||||
final PremiumList premiumList, ImmutableMap<String, PremiumListEntry> premiumListEntries) {
|
|
||||||
final Optional<PremiumList> oldPremiumList = get(premiumList.getName());
|
|
||||||
|
|
||||||
// Create the new revision (with its bloom filter) and parent the entries on it.
|
|
||||||
final PremiumListRevision newRevision =
|
|
||||||
PremiumListRevision.create(premiumList, premiumListEntries.keySet());
|
|
||||||
final Key<PremiumListRevision> newRevisionKey = Key.create(newRevision);
|
|
||||||
ImmutableSet<PremiumListEntry> parentedEntries =
|
|
||||||
parentEntriesOnRevision(
|
|
||||||
firstNonNull(premiumListEntries.values(), ImmutableSet.of()), newRevisionKey);
|
|
||||||
|
|
||||||
// Save the new child entities in a series of transactions.
|
|
||||||
for (final List<PremiumListEntry> batch : partition(parentedEntries, TRANSACTION_BATCH_SIZE)) {
|
|
||||||
ofy().transactNew(new VoidWork() {
|
|
||||||
@Override
|
|
||||||
public void vrun() {
|
|
||||||
ofy().save().entities(batch);
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the new PremiumList and revision itself.
|
|
||||||
PremiumList updated = ofy().transactNew(new Work<PremiumList>() {
|
|
||||||
@Override
|
|
||||||
public PremiumList run() {
|
|
||||||
DateTime now = ofy().getTransactionTime();
|
|
||||||
// Assert that the premium list hasn't been changed since we started this process.
|
|
||||||
PremiumList existing = ofy().load()
|
|
||||||
.type(PremiumList.class)
|
|
||||||
.parent(getCrossTldKey())
|
|
||||||
.id(premiumList.getName())
|
|
||||||
.now();
|
|
||||||
checkState(
|
|
||||||
Objects.equals(existing, oldPremiumList.orNull()),
|
|
||||||
"PremiumList was concurrently edited");
|
|
||||||
PremiumList newList = premiumList.asBuilder()
|
|
||||||
.setLastUpdateTime(now)
|
|
||||||
.setCreationTime(
|
|
||||||
oldPremiumList.isPresent() ? oldPremiumList.get().creationTime : now)
|
|
||||||
.setRevision(newRevisionKey)
|
|
||||||
.build();
|
|
||||||
ofy().save().entities(newList, newRevision);
|
|
||||||
return newList;
|
|
||||||
}});
|
|
||||||
// Update the cache.
|
|
||||||
cachePremiumLists.put(premiumList.getName(), updated);
|
|
||||||
// Delete the entities under the old PremiumList.
|
|
||||||
if (oldPremiumList.isPresent()) {
|
|
||||||
oldPremiumList.get().deleteRevisionAndEntries();
|
|
||||||
}
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean refersToKey(Registry registry, Key<? extends BaseDomainLabelList<?, ?>> key) {
|
public boolean refersToKey(Registry registry, Key<? extends BaseDomainLabelList<?, ?>> key) {
|
||||||
return Objects.equals(registry.getPremiumList(), key);
|
return Objects.equals(registry.getPremiumList(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Deletes the PremiumList and all of its child entities. */
|
Query<PremiumListEntry> queryEntriesForCurrentRevision() {
|
||||||
public void delete() {
|
|
||||||
ofy().transactNew(new VoidWork() {
|
|
||||||
@Override
|
|
||||||
public void vrun() {
|
|
||||||
ofy().delete().entity(PremiumList.this);
|
|
||||||
}});
|
|
||||||
deleteRevisionAndEntries();
|
|
||||||
cachePremiumLists.invalidate(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteRevisionAndEntries() {
|
|
||||||
if (revisionKey == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (final List<Key<PremiumListEntry>> batch : partition(
|
|
||||||
queryEntriesForCurrentRevision().keys(),
|
|
||||||
TRANSACTION_BATCH_SIZE)) {
|
|
||||||
ofy().transactNew(new VoidWork() {
|
|
||||||
@Override
|
|
||||||
public void vrun() {
|
|
||||||
ofy().delete().keys(batch);
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
ofy().transactNew(new VoidWork() {
|
|
||||||
@Override
|
|
||||||
public void vrun() {
|
|
||||||
ofy().delete().key(revisionKey);
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
|
|
||||||
private Query<PremiumListEntry> queryEntriesForCurrentRevision() {
|
|
||||||
return ofy().load().type(PremiumListEntry.class).ancestor(revisionKey);
|
return ofy().load().type(PremiumListEntry.class).ancestor(revisionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
234
java/google/registry/model/registry/label/PremiumListUtils.java
Normal file
234
java/google/registry/model/registry/label/PremiumListUtils.java
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
// Copyright 2017 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.model.registry.label;
|
||||||
|
|
||||||
|
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
import static com.google.common.collect.Iterables.partition;
|
||||||
|
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||||
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
|
import static google.registry.model.registry.label.PremiumList.cachePremiumListEntries;
|
||||||
|
import static google.registry.model.registry.label.PremiumList.cachePremiumListRevisions;
|
||||||
|
import static google.registry.model.registry.label.PremiumList.cachePremiumLists;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
|
||||||
|
import com.google.common.collect.FluentIterable;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.googlecode.objectify.Key;
|
||||||
|
import com.googlecode.objectify.VoidWork;
|
||||||
|
import com.googlecode.objectify.Work;
|
||||||
|
import google.registry.model.registry.Registry;
|
||||||
|
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
||||||
|
import google.registry.model.registry.label.PremiumList.PremiumListRevision;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import org.joda.money.Money;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
/** Static helper methods for working with {@link PremiumList}s. */
|
||||||
|
public final class PremiumListUtils {
|
||||||
|
|
||||||
|
/** The number of premium list entry entities that are created and deleted per batch. */
|
||||||
|
static final int TRANSACTION_BATCH_SIZE = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the premium price for the specified label and registry, or absent if the label is not
|
||||||
|
* premium.
|
||||||
|
*/
|
||||||
|
public static Optional<Money> getPremiumPrice(String label, Registry registry) {
|
||||||
|
// If the registry has no configured premium list, then no labels are premium.
|
||||||
|
if (registry.getPremiumList() == null) {
|
||||||
|
return Optional.<Money> absent();
|
||||||
|
}
|
||||||
|
String listName = registry.getPremiumList().getName();
|
||||||
|
Optional<PremiumList> optionalPremiumList = PremiumList.get(listName);
|
||||||
|
checkState(optionalPremiumList.isPresent(), "Could not load premium list '%s'", listName);
|
||||||
|
PremiumList premiumList = optionalPremiumList.get();
|
||||||
|
PremiumListRevision revision;
|
||||||
|
try {
|
||||||
|
revision = cachePremiumListRevisions.get(premiumList.getRevisionKey());
|
||||||
|
} catch (InvalidCacheLoadException | ExecutionException e) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Could not load premium list revision " + premiumList.getRevisionKey(), e);
|
||||||
|
}
|
||||||
|
checkState(
|
||||||
|
revision.probablePremiumLabels != null,
|
||||||
|
"Probable premium labels bloom filter is null on revision '%s'",
|
||||||
|
premiumList.getRevisionKey());
|
||||||
|
|
||||||
|
if (revision.probablePremiumLabels.mightContain(label)) {
|
||||||
|
Key<PremiumListEntry> entryKey =
|
||||||
|
Key.create(premiumList.getRevisionKey(), PremiumListEntry.class, label);
|
||||||
|
try {
|
||||||
|
Optional<PremiumListEntry> entry = cachePremiumListEntries.get(entryKey);
|
||||||
|
return (entry.isPresent()) ? Optional.of(entry.get().getValue()) : Optional.<Money>absent();
|
||||||
|
} catch (InvalidCacheLoadException | ExecutionException e) {
|
||||||
|
throw new RuntimeException("Could not load premium list entry " + entryKey, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Optional.<Money>absent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists a new or updated PremiumList object and its descendant entities to Datastore.
|
||||||
|
*
|
||||||
|
* <p>The flow here is: save the new premium list entries parented on that revision entity,
|
||||||
|
* save/update the PremiumList, and then delete the old premium list entries associated with the
|
||||||
|
* old revision.
|
||||||
|
*
|
||||||
|
* <p>This is the only valid way to save these kinds of entities!
|
||||||
|
*/
|
||||||
|
public static PremiumList savePremiumListAndEntries(
|
||||||
|
final PremiumList premiumList,
|
||||||
|
ImmutableMap<String, PremiumListEntry> premiumListEntries) {
|
||||||
|
final Optional<PremiumList> oldPremiumList = PremiumList.get(premiumList.getName());
|
||||||
|
|
||||||
|
// Create the new revision (with its bloom filter) and parent the entries on it.
|
||||||
|
final PremiumListRevision newRevision =
|
||||||
|
PremiumListRevision.create(premiumList, premiumListEntries.keySet());
|
||||||
|
final Key<PremiumListRevision> newRevisionKey = Key.create(newRevision);
|
||||||
|
ImmutableSet<PremiumListEntry> parentedEntries =
|
||||||
|
parentPremiumListEntriesOnRevision(
|
||||||
|
firstNonNull(premiumListEntries.values(), ImmutableSet.of()), newRevisionKey);
|
||||||
|
|
||||||
|
// Save the new child entities in a series of transactions.
|
||||||
|
for (final List<PremiumListEntry> batch :
|
||||||
|
partition(parentedEntries, TRANSACTION_BATCH_SIZE)) {
|
||||||
|
ofy().transactNew(new VoidWork() {
|
||||||
|
@Override
|
||||||
|
public void vrun() {
|
||||||
|
ofy().save().entities(batch);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the new PremiumList and revision itself.
|
||||||
|
PremiumList updated = ofy().transactNew(new Work<PremiumList>() {
|
||||||
|
@Override
|
||||||
|
public PremiumList run() {
|
||||||
|
DateTime now = ofy().getTransactionTime();
|
||||||
|
// Assert that the premium list hasn't been changed since we started this process.
|
||||||
|
PremiumList existing = ofy().load()
|
||||||
|
.type(PremiumList.class)
|
||||||
|
.parent(getCrossTldKey())
|
||||||
|
.id(premiumList.getName())
|
||||||
|
.now();
|
||||||
|
checkState(
|
||||||
|
Objects.equals(existing, oldPremiumList.orNull()),
|
||||||
|
"PremiumList was concurrently edited");
|
||||||
|
PremiumList newList = premiumList.asBuilder()
|
||||||
|
.setLastUpdateTime(now)
|
||||||
|
.setCreationTime(
|
||||||
|
oldPremiumList.isPresent() ? oldPremiumList.get().creationTime : now)
|
||||||
|
.setRevision(newRevisionKey)
|
||||||
|
.build();
|
||||||
|
ofy().save().entities(newList, newRevision);
|
||||||
|
return newList;
|
||||||
|
}});
|
||||||
|
// Update the cache.
|
||||||
|
cachePremiumLists.put(premiumList.getName(), updated);
|
||||||
|
// Delete the entities under the old PremiumList.
|
||||||
|
if (oldPremiumList.isPresent()) {
|
||||||
|
deleteRevisionAndEntriesOfPremiumList(oldPremiumList.get());
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PremiumList savePremiumListAndEntries(
|
||||||
|
PremiumList premiumList, Iterable<String> premiumListLines) {
|
||||||
|
return savePremiumListAndEntries(premiumList, premiumList.parse(premiumListLines));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Re-parents the given {@link PremiumListEntry}s on the given {@link PremiumListRevision}. */
|
||||||
|
public static ImmutableSet<PremiumListEntry> parentPremiumListEntriesOnRevision(
|
||||||
|
Iterable<PremiumListEntry> entries, final Key<PremiumListRevision> revisionKey) {
|
||||||
|
return FluentIterable.from(firstNonNull(entries, ImmutableSet.of()))
|
||||||
|
.transform(
|
||||||
|
new Function<PremiumListEntry, PremiumListEntry>() {
|
||||||
|
@Override
|
||||||
|
public PremiumListEntry apply(PremiumListEntry entry) {
|
||||||
|
return entry.asBuilder().setParent(revisionKey).build();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.toSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deletes the PremiumList and all of its child entities. */
|
||||||
|
public static void deletePremiumList(final PremiumList premiumList) {
|
||||||
|
ofy().transactNew(new VoidWork() {
|
||||||
|
@Override
|
||||||
|
public void vrun() {
|
||||||
|
ofy().delete().entity(premiumList);
|
||||||
|
}});
|
||||||
|
deleteRevisionAndEntriesOfPremiumList(premiumList);
|
||||||
|
cachePremiumLists.invalidate(premiumList.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deleteRevisionAndEntriesOfPremiumList(final PremiumList premiumList) {
|
||||||
|
if (premiumList.getRevisionKey() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (final List<Key<PremiumListEntry>> batch : partition(
|
||||||
|
premiumList.queryEntriesForCurrentRevision().keys(),
|
||||||
|
TRANSACTION_BATCH_SIZE)) {
|
||||||
|
ofy().transactNew(new VoidWork() {
|
||||||
|
@Override
|
||||||
|
public void vrun() {
|
||||||
|
ofy().delete().keys(batch);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
ofy().transactNew(new VoidWork() {
|
||||||
|
@Override
|
||||||
|
public void vrun() {
|
||||||
|
ofy().delete().key(premiumList.getRevisionKey());
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns whether a PremiumList of the given name exists, bypassing the cache. */
|
||||||
|
public static boolean doesPremiumListExist(String name) {
|
||||||
|
return ofy().load().key(Key.create(getCrossTldKey(), PremiumList.class, name)).now() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads and returns the entire premium list map.
|
||||||
|
*
|
||||||
|
* <p>This load operation is quite expensive for large premium lists because each premium list
|
||||||
|
* entry is a separate Datastore entity, and loading them this way bypasses the in-memory caches.
|
||||||
|
* Do not use this method if all you need to do is check the price of a small number of labels!
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public static Map<String, PremiumListEntry> loadPremiumListEntries(PremiumList premiumList) {
|
||||||
|
try {
|
||||||
|
ImmutableMap.Builder<String, PremiumListEntry> entriesMap = new ImmutableMap.Builder<>();
|
||||||
|
if (premiumList.getRevisionKey() != null) {
|
||||||
|
for (PremiumListEntry entry : premiumList.queryEntriesForCurrentRevision()) {
|
||||||
|
entriesMap.put(entry.getLabel(), entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entriesMap.build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Could not retrieve entries for premium list " + premiumList.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PremiumListUtils() {}
|
||||||
|
}
|
|
@ -15,6 +15,8 @@
|
||||||
package google.registry.tools;
|
package google.registry.tools;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.deletePremiumList;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.doesPremiumListExist;
|
||||||
|
|
||||||
import com.beust.jcommander.Parameter;
|
import com.beust.jcommander.Parameter;
|
||||||
import com.beust.jcommander.Parameters;
|
import com.beust.jcommander.Parameters;
|
||||||
|
@ -43,7 +45,7 @@ final class DeletePremiumListCommand extends ConfirmingCommand implements Remote
|
||||||
@Override
|
@Override
|
||||||
protected void init() throws Exception {
|
protected void init() throws Exception {
|
||||||
checkArgument(
|
checkArgument(
|
||||||
PremiumList.exists(name),
|
doesPremiumListExist(name),
|
||||||
"Cannot delete the premium list %s because it doesn't exist.",
|
"Cannot delete the premium list %s because it doesn't exist.",
|
||||||
name);
|
name);
|
||||||
premiumList = PremiumList.get(name).get();
|
premiumList = PremiumList.get(name).get();
|
||||||
|
@ -61,7 +63,7 @@ final class DeletePremiumListCommand extends ConfirmingCommand implements Remote
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String execute() throws Exception {
|
protected String execute() throws Exception {
|
||||||
premiumList.delete();
|
deletePremiumList(premiumList);
|
||||||
return String.format("Deleted premium list '%s'.\n", premiumList.getName());
|
return String.format("Deleted premium list '%s'.\n", premiumList.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ package google.registry.tools.server;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static google.registry.model.registry.Registries.assertTldExists;
|
import static google.registry.model.registry.Registries.assertTldExists;
|
||||||
import static google.registry.model.registry.label.PremiumList.saveWithEntries;
|
import static google.registry.model.registry.label.PremiumListUtils.doesPremiumListExist;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
||||||
import static google.registry.request.Action.Method.POST;
|
import static google.registry.request.Action.Method.POST;
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
@ -43,8 +44,7 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||||
@Override
|
@Override
|
||||||
protected void savePremiumList() {
|
protected void savePremiumList() {
|
||||||
checkArgument(
|
checkArgument(
|
||||||
!PremiumList.exists(name),
|
!doesPremiumListExist(name), "A premium list of this name already exists: %s.", name);
|
||||||
"A premium list of this name already exists: %s.", name);
|
|
||||||
if (!override) {
|
if (!override) {
|
||||||
assertTldExists(name);
|
assertTldExists(name);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||||
List<String> inputDataPreProcessed =
|
List<String> inputDataPreProcessed =
|
||||||
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
||||||
PremiumList premiumList = new PremiumList.Builder().setName(name).build();
|
PremiumList premiumList = new PremiumList.Builder().setName(name).build();
|
||||||
saveWithEntries(premiumList, inputDataPreProcessed);
|
savePremiumListAndEntries(premiumList, inputDataPreProcessed);
|
||||||
|
|
||||||
String message =
|
String message =
|
||||||
String.format(
|
String.format(
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
package google.registry.tools.server;
|
package google.registry.tools.server;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static google.registry.model.registry.label.PremiumList.saveWithEntries;
|
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
||||||
import static google.registry.request.Action.Method.POST;
|
import static google.registry.request.Action.Method.POST;
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
|
@ -49,7 +49,8 @@ public class UpdatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||||
logger.infofmt("Got the following input data: %s", inputData);
|
logger.infofmt("Got the following input data: %s", inputData);
|
||||||
List<String> inputDataPreProcessed =
|
List<String> inputDataPreProcessed =
|
||||||
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
||||||
PremiumList newPremiumList = saveWithEntries(existingPremiumList.get(), inputDataPreProcessed);
|
PremiumList newPremiumList =
|
||||||
|
savePremiumListAndEntries(existingPremiumList.get(), inputDataPreProcessed);
|
||||||
|
|
||||||
String message =
|
String message =
|
||||||
String.format(
|
String.format(
|
||||||
|
|
|
@ -17,9 +17,6 @@ package google.registry.model.registry.label;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.model.registry.label.PremiumList.cachePremiumListEntries;
|
|
||||||
import static google.registry.model.registry.label.PremiumList.getPremiumPrice;
|
|
||||||
import static google.registry.model.registry.label.PremiumList.saveWithEntries;
|
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
||||||
import static google.registry.testing.DatastoreHelper.persistReservedList;
|
import static google.registry.testing.DatastoreHelper.persistReservedList;
|
||||||
|
@ -28,14 +25,11 @@ import static google.registry.testing.DatastoreHelper.persistResource;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import google.registry.model.pricing.StaticPremiumListPricingEngine;
|
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
||||||
import google.registry.model.registry.label.PremiumList.PremiumListRevision;
|
import google.registry.model.registry.label.PremiumList.PremiumListRevision;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.ExceptionRule;
|
import google.registry.testing.ExceptionRule;
|
||||||
import java.util.Map;
|
|
||||||
import org.joda.money.Money;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -46,19 +40,15 @@ import org.junit.runners.JUnit4;
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class PremiumListTest {
|
public class PremiumListTest {
|
||||||
|
|
||||||
@Rule
|
@Rule public final ExceptionRule thrown = new ExceptionRule();
|
||||||
public final ExceptionRule thrown = new ExceptionRule();
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
|
||||||
.withDatastore()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
// createTld() overwrites the premium list, so call it first.
|
// createTld() overwrites the premium list, so call it first.
|
||||||
createTld("tld");
|
createTld("tld");
|
||||||
PremiumList pl = persistPremiumList(
|
PremiumList pl =
|
||||||
|
persistPremiumList(
|
||||||
"tld",
|
"tld",
|
||||||
"lol,USD 999 # yup",
|
"lol,USD 999 # yup",
|
||||||
"rich,USD 1999 #tada",
|
"rich,USD 1999 #tada",
|
||||||
|
@ -67,153 +57,6 @@ public class PremiumListTest {
|
||||||
persistResource(Registry.get("tld").asBuilder().setPremiumList(pl).build());
|
persistResource(Registry.get("tld").asBuilder().setPremiumList(pl).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPremiumPrice_returnsNoPriceWhenNoPremiumListConfigured() throws Exception {
|
|
||||||
createTld("ghost");
|
|
||||||
persistResource(
|
|
||||||
new Registry.Builder()
|
|
||||||
.setTldStr("ghost")
|
|
||||||
.setPremiumPricingEngine(StaticPremiumListPricingEngine.NAME)
|
|
||||||
.build());
|
|
||||||
assertThat(Registry.get("ghost").getPremiumList()).isNull();
|
|
||||||
assertThat(getPremiumPrice("blah", Registry.get("ghost"))).isAbsent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPremiumPrice_throwsExceptionWhenNonExistentPremiumListConfigured()
|
|
||||||
throws Exception {
|
|
||||||
PremiumList.get("tld").get().delete();
|
|
||||||
thrown.expect(IllegalStateException.class, "Could not load premium list 'tld'");
|
|
||||||
getPremiumPrice("blah", Registry.get("tld"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSave_largeNumberOfEntries_succeeds() throws Exception {
|
|
||||||
PremiumList premiumList = persistHumongousPremiumList("tld", 2500);
|
|
||||||
assertThat(premiumList.loadPremiumListEntries()).hasSize(2500);
|
|
||||||
assertThat(getPremiumPrice("7", Registry.get("tld"))).hasValue(Money.parse("USD 100"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSave_updateTime_isUpdatedOnEverySave() throws Exception {
|
|
||||||
PremiumList pl =
|
|
||||||
saveWithEntries(
|
|
||||||
new PremiumList.Builder().setName("tld3").build(), ImmutableList.of("slime,USD 10"));
|
|
||||||
PremiumList newPl =
|
|
||||||
saveWithEntries(
|
|
||||||
new PremiumList.Builder().setName(pl.getName()).build(),
|
|
||||||
ImmutableList.of("mutants,USD 20"));
|
|
||||||
assertThat(newPl.getLastUpdateTime()).isGreaterThan(pl.getLastUpdateTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSave_creationTime_onlyUpdatedOnFirstCreation() throws Exception {
|
|
||||||
PremiumList pl = persistPremiumList("tld3", "sludge,JPY 1000");
|
|
||||||
PremiumList newPl = saveWithEntries(pl, ImmutableList.of("sleighbells,CHF 2000"));
|
|
||||||
assertThat(newPl.creationTime).isEqualTo(pl.creationTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSave_removedPremiumListEntries_areNoLongerInDatastore() throws Exception {
|
|
||||||
Registry registry = Registry.get("tld");
|
|
||||||
PremiumList pl = persistPremiumList("tld", "genius,USD 10", "dolt,JPY 1000");
|
|
||||||
assertThat(getPremiumPrice("genius", registry)).hasValue(Money.parse("USD 10"));
|
|
||||||
assertThat(getPremiumPrice("dolt", registry)).hasValue(Money.parse("JPY 1000"));
|
|
||||||
assertThat(ofy()
|
|
||||||
.load()
|
|
||||||
.type(PremiumListEntry.class)
|
|
||||||
.parent(pl.getRevisionKey())
|
|
||||||
.id("dolt")
|
|
||||||
.now()
|
|
||||||
.price)
|
|
||||||
.isEqualTo(Money.parse("JPY 1000"));
|
|
||||||
PremiumList pl2 = saveWithEntries(pl, ImmutableList.of("genius,USD 10", "savant,USD 90"));
|
|
||||||
assertThat(getPremiumPrice("genius", registry)).hasValue(Money.parse("USD 10"));
|
|
||||||
assertThat(getPremiumPrice("savant", registry)).hasValue(Money.parse("USD 90"));
|
|
||||||
assertThat(getPremiumPrice("dolt", registry)).isAbsent();
|
|
||||||
assertThat(ofy()
|
|
||||||
.load()
|
|
||||||
.type(PremiumListEntry.class)
|
|
||||||
.parent(pl.getRevisionKey())
|
|
||||||
.id("dolt")
|
|
||||||
.now())
|
|
||||||
.isNull();
|
|
||||||
assertThat(ofy()
|
|
||||||
.load()
|
|
||||||
.type(PremiumListEntry.class)
|
|
||||||
.parent(pl2.getRevisionKey())
|
|
||||||
.id("dolt")
|
|
||||||
.now())
|
|
||||||
.isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPremiumPrice_allLabelsAreNonPremium_whenNotInList() throws Exception {
|
|
||||||
assertThat(getPremiumPrice("blah", Registry.get("tld"))).isAbsent();
|
|
||||||
assertThat(getPremiumPrice("slinge", Registry.get("tld"))).isAbsent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSave_simple() throws Exception {
|
|
||||||
PremiumList pl =
|
|
||||||
saveWithEntries(
|
|
||||||
new PremiumList.Builder().setName("tld2").build(),
|
|
||||||
ImmutableList.of("lol , USD 999 # yupper rooni "));
|
|
||||||
createTld("tld");
|
|
||||||
persistResource(Registry.get("tld").asBuilder().setPremiumList(pl).build());
|
|
||||||
assertThat(getPremiumPrice("lol", Registry.get("tld"))).hasValue(Money.parse("USD 999"));
|
|
||||||
assertThat(getPremiumPrice("lol ", Registry.get("tld"))).isAbsent();
|
|
||||||
Map<String, PremiumListEntry> entries =
|
|
||||||
PremiumList.get("tld2").get().loadPremiumListEntries();
|
|
||||||
assertThat(entries.keySet()).containsExactly("lol");
|
|
||||||
assertThat(entries).doesNotContainKey("lol ");
|
|
||||||
PremiumListEntry entry = entries.get("lol");
|
|
||||||
assertThat(entry.comment).isEqualTo("yupper rooni");
|
|
||||||
assertThat(entry.price).isEqualTo(Money.parse("USD 999"));
|
|
||||||
assertThat(entry.label).isEqualTo("lol");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_saveAndUpdateEntriesTwice() throws Exception {
|
|
||||||
PremiumList pl =
|
|
||||||
saveWithEntries(
|
|
||||||
new PremiumList.Builder().setName("pl").build(), ImmutableList.of("test,USD 1"));
|
|
||||||
Map<String, PremiumListEntry> entries = pl.loadPremiumListEntries();
|
|
||||||
assertThat(entries.keySet()).containsExactly("test");
|
|
||||||
assertThat(PremiumList.get("pl").get().loadPremiumListEntries()).isEqualTo(entries);
|
|
||||||
// Save again with no changes, and clear the cache to force a re-load from Datastore.
|
|
||||||
PremiumList resaved = saveWithEntries(pl, ImmutableList.of("test,USD 1"));
|
|
||||||
ofy().clearSessionCache();
|
|
||||||
Map<String, PremiumListEntry> entriesReloaded =
|
|
||||||
PremiumList.get("pl").get().loadPremiumListEntries();
|
|
||||||
assertThat(entriesReloaded).hasSize(1);
|
|
||||||
assertThat(entriesReloaded).containsKey("test");
|
|
||||||
assertThat(entriesReloaded.get("test").parent).isEqualTo(resaved.getRevisionKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDelete() throws Exception {
|
|
||||||
persistPremiumList("gtld1", "trombone,USD 10");
|
|
||||||
assertThat(PremiumList.get("gtld1")).isPresent();
|
|
||||||
Key<PremiumListRevision> parent = PremiumList.get("gtld1").get().getRevisionKey();
|
|
||||||
PremiumList.get("gtld1").get().delete();
|
|
||||||
assertThat(PremiumList.get("gtld1")).isAbsent();
|
|
||||||
assertThat(ofy().load().type(PremiumListEntry.class).ancestor(parent).list()).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDelete_largeNumberOfEntries_succeeds() {
|
|
||||||
persistHumongousPremiumList("ginormous", 2500);
|
|
||||||
PremiumList.get("ginormous").get().delete();
|
|
||||||
assertThat(PremiumList.get("ginormous")).isAbsent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDelete_failsWhenListDoesntExist() throws Exception {
|
|
||||||
thrown.expect(IllegalStateException.class);
|
|
||||||
PremiumList.get("tld-premium-blah").get().delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSave_badSyntax() throws Exception {
|
public void testSave_badSyntax() throws Exception {
|
||||||
thrown.expect(IllegalArgumentException.class);
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
@ -226,32 +69,6 @@ public class PremiumListTest {
|
||||||
persistReservedList("gtld1", "lol,XBTC 200");
|
persistReservedList("gtld1", "lol,XBTC 200");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExists() throws Exception {
|
|
||||||
assertThat(PremiumList.exists("tld")).isTrue();
|
|
||||||
assertThat(PremiumList.exists("nonExistentPremiumList")).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPremiumPrice_comesFromBloomFilter() throws Exception {
|
|
||||||
PremiumList pl = PremiumList.get("tld").get();
|
|
||||||
PremiumListEntry entry =
|
|
||||||
persistResource(
|
|
||||||
new PremiumListEntry.Builder()
|
|
||||||
.setParent(pl.getRevisionKey())
|
|
||||||
.setLabel("missingno")
|
|
||||||
.setPrice(Money.parse("USD 1000"))
|
|
||||||
.build());
|
|
||||||
// "missingno" shouldn't be in the bloom filter, thus it should return not premium without
|
|
||||||
// attempting to load the entity that is actually present.
|
|
||||||
assertThat(getPremiumPrice("missingno", Registry.get("tld"))).isAbsent();
|
|
||||||
// However, if we manually query the cache to force an entity load, it should be found.
|
|
||||||
assertThat(
|
|
||||||
cachePremiumListEntries.get(
|
|
||||||
Key.create(pl.getRevisionKey(), PremiumListEntry.class, "missingno")))
|
|
||||||
.hasValue(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProbablePremiumLabels() throws Exception {
|
public void testProbablePremiumLabels() throws Exception {
|
||||||
PremiumList pl = PremiumList.get("tld").get();
|
PremiumList pl = PremiumList.get("tld").get();
|
||||||
|
@ -276,15 +93,6 @@ public class PremiumListTest {
|
||||||
"lol,USD 100", "rofl,USD 90", "paper,USD 80", "wood,USD 70", "lol,USD 200"));
|
"lol,USD 100", "rofl,USD 90", "paper,USD 80", "wood,USD 70", "lol,USD 200"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Persists a premium list with a specified number of nonsense entries. */
|
|
||||||
private PremiumList persistHumongousPremiumList(String name, int size) {
|
|
||||||
String[] entries = new String[size];
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
entries[i] = String.format("%d,USD 100 # blahz", i);
|
|
||||||
}
|
|
||||||
return persistPremiumList(name, entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the label of a premium list entry. */
|
/** Gets the label of a premium list entry. */
|
||||||
public static final Function<Key<PremiumListEntry>, String> GET_ENTRY_NAME_FUNCTION =
|
public static final Function<Key<PremiumListEntry>, String> GET_ENTRY_NAME_FUNCTION =
|
||||||
new Function<Key<PremiumListEntry>, String>() {
|
new Function<Key<PremiumListEntry>, String>() {
|
||||||
|
|
|
@ -0,0 +1,248 @@
|
||||||
|
// Copyright 2017 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.model.registry.label;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
|
import static google.registry.model.registry.label.PremiumList.cachePremiumListEntries;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.deletePremiumList;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.doesPremiumListExist;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.loadPremiumListEntries;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
||||||
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
|
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
||||||
|
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.googlecode.objectify.Key;
|
||||||
|
import google.registry.model.pricing.StaticPremiumListPricingEngine;
|
||||||
|
import google.registry.model.registry.Registry;
|
||||||
|
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
||||||
|
import google.registry.model.registry.label.PremiumList.PremiumListRevision;
|
||||||
|
import google.registry.testing.AppEngineRule;
|
||||||
|
import google.registry.testing.ExceptionRule;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.joda.money.Money;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
/** Unit tests for {@link PremiumListUtils}. */
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class PremiumListUtilsTest {
|
||||||
|
|
||||||
|
@Rule public final ExceptionRule thrown = new ExceptionRule();
|
||||||
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws Exception {
|
||||||
|
// createTld() overwrites the premium list, so call it first.
|
||||||
|
createTld("tld");
|
||||||
|
PremiumList pl =
|
||||||
|
persistPremiumList(
|
||||||
|
"tld",
|
||||||
|
"lol,USD 999 # yup",
|
||||||
|
"rich,USD 1999 #tada",
|
||||||
|
"icann,JPY 100",
|
||||||
|
"johnny-be-goode,USD 20.50");
|
||||||
|
persistResource(Registry.get("tld").asBuilder().setPremiumList(pl).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPremiumPrice_returnsNoPriceWhenNoPremiumListConfigured() throws Exception {
|
||||||
|
createTld("ghost");
|
||||||
|
persistResource(
|
||||||
|
new Registry.Builder()
|
||||||
|
.setTldStr("ghost")
|
||||||
|
.setPremiumPricingEngine(StaticPremiumListPricingEngine.NAME)
|
||||||
|
.build());
|
||||||
|
assertThat(Registry.get("ghost").getPremiumList()).isNull();
|
||||||
|
assertThat(getPremiumPrice("blah", Registry.get("ghost"))).isAbsent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPremiumPrice_throwsExceptionWhenNonExistentPremiumListConfigured()
|
||||||
|
throws Exception {
|
||||||
|
deletePremiumList(PremiumList.get("tld").get());
|
||||||
|
thrown.expect(IllegalStateException.class, "Could not load premium list 'tld'");
|
||||||
|
getPremiumPrice("blah", Registry.get("tld"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSave_largeNumberOfEntries_succeeds() throws Exception {
|
||||||
|
PremiumList premiumList = persistHumongousPremiumList("tld", 2500);
|
||||||
|
assertThat(loadPremiumListEntries(premiumList)).hasSize(2500);
|
||||||
|
assertThat(getPremiumPrice("7", Registry.get("tld"))).hasValue(Money.parse("USD 100"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSave_updateTime_isUpdatedOnEverySave() throws Exception {
|
||||||
|
PremiumList pl =
|
||||||
|
savePremiumListAndEntries(
|
||||||
|
new PremiumList.Builder().setName("tld3").build(), ImmutableList.of("slime,USD 10"));
|
||||||
|
PremiumList newPl =
|
||||||
|
savePremiumListAndEntries(
|
||||||
|
new PremiumList.Builder().setName(pl.getName()).build(),
|
||||||
|
ImmutableList.of("mutants,USD 20"));
|
||||||
|
assertThat(newPl.getLastUpdateTime()).isGreaterThan(pl.getLastUpdateTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSave_creationTime_onlyUpdatedOnFirstCreation() throws Exception {
|
||||||
|
PremiumList pl = persistPremiumList("tld3", "sludge,JPY 1000");
|
||||||
|
PremiumList newPl = savePremiumListAndEntries(pl, ImmutableList.of("sleighbells,CHF 2000"));
|
||||||
|
assertThat(newPl.creationTime).isEqualTo(pl.creationTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExists() throws Exception {
|
||||||
|
assertThat(doesPremiumListExist("tld")).isTrue();
|
||||||
|
assertThat(doesPremiumListExist("nonExistentPremiumList")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPremiumPrice_comesFromBloomFilter() throws Exception {
|
||||||
|
PremiumList pl = PremiumList.get("tld").get();
|
||||||
|
PremiumListEntry entry =
|
||||||
|
persistResource(
|
||||||
|
new PremiumListEntry.Builder()
|
||||||
|
.setParent(pl.getRevisionKey())
|
||||||
|
.setLabel("missingno")
|
||||||
|
.setPrice(Money.parse("USD 1000"))
|
||||||
|
.build());
|
||||||
|
// "missingno" shouldn't be in the bloom filter, thus it should return not premium without
|
||||||
|
// attempting to load the entity that is actually present.
|
||||||
|
assertThat(getPremiumPrice("missingno", Registry.get("tld"))).isAbsent();
|
||||||
|
// However, if we manually query the cache to force an entity load, it should be found.
|
||||||
|
assertThat(
|
||||||
|
cachePremiumListEntries.get(
|
||||||
|
Key.create(pl.getRevisionKey(), PremiumListEntry.class, "missingno")))
|
||||||
|
.hasValue(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSave_removedPremiumListEntries_areNoLongerInDatastore() throws Exception {
|
||||||
|
Registry registry = Registry.get("tld");
|
||||||
|
PremiumList pl = persistPremiumList("tld", "genius,USD 10", "dolt,JPY 1000");
|
||||||
|
assertThat(getPremiumPrice("genius", registry)).hasValue(Money.parse("USD 10"));
|
||||||
|
assertThat(getPremiumPrice("dolt", registry)).hasValue(Money.parse("JPY 1000"));
|
||||||
|
assertThat(ofy()
|
||||||
|
.load()
|
||||||
|
.type(PremiumListEntry.class)
|
||||||
|
.parent(pl.getRevisionKey())
|
||||||
|
.id("dolt")
|
||||||
|
.now()
|
||||||
|
.price)
|
||||||
|
.isEqualTo(Money.parse("JPY 1000"));
|
||||||
|
PremiumList pl2 =
|
||||||
|
savePremiumListAndEntries(pl, ImmutableList.of("genius,USD 10", "savant,USD 90"));
|
||||||
|
assertThat(getPremiumPrice("genius", registry)).hasValue(Money.parse("USD 10"));
|
||||||
|
assertThat(getPremiumPrice("savant", registry)).hasValue(Money.parse("USD 90"));
|
||||||
|
assertThat(getPremiumPrice("dolt", registry)).isAbsent();
|
||||||
|
assertThat(ofy()
|
||||||
|
.load()
|
||||||
|
.type(PremiumListEntry.class)
|
||||||
|
.parent(pl.getRevisionKey())
|
||||||
|
.id("dolt")
|
||||||
|
.now())
|
||||||
|
.isNull();
|
||||||
|
assertThat(ofy()
|
||||||
|
.load()
|
||||||
|
.type(PremiumListEntry.class)
|
||||||
|
.parent(pl2.getRevisionKey())
|
||||||
|
.id("dolt")
|
||||||
|
.now())
|
||||||
|
.isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPremiumPrice_allLabelsAreNonPremium_whenNotInList() throws Exception {
|
||||||
|
assertThat(getPremiumPrice("blah", Registry.get("tld"))).isAbsent();
|
||||||
|
assertThat(getPremiumPrice("slinge", Registry.get("tld"))).isAbsent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSave_simple() throws Exception {
|
||||||
|
PremiumList pl =
|
||||||
|
savePremiumListAndEntries(
|
||||||
|
new PremiumList.Builder().setName("tld2").build(),
|
||||||
|
ImmutableList.of("lol , USD 999 # yupper rooni "));
|
||||||
|
createTld("tld");
|
||||||
|
persistResource(Registry.get("tld").asBuilder().setPremiumList(pl).build());
|
||||||
|
assertThat(getPremiumPrice("lol", Registry.get("tld"))).hasValue(Money.parse("USD 999"));
|
||||||
|
assertThat(getPremiumPrice("lol ", Registry.get("tld"))).isAbsent();
|
||||||
|
Map<String, PremiumListEntry> entries = loadPremiumListEntries(PremiumList.get("tld2").get());
|
||||||
|
assertThat(entries.keySet()).containsExactly("lol");
|
||||||
|
assertThat(entries).doesNotContainKey("lol ");
|
||||||
|
PremiumListEntry entry = entries.get("lol");
|
||||||
|
assertThat(entry.comment).isEqualTo("yupper rooni");
|
||||||
|
assertThat(entry.price).isEqualTo(Money.parse("USD 999"));
|
||||||
|
assertThat(entry.label).isEqualTo("lol");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_saveAndUpdateEntriesTwice() throws Exception {
|
||||||
|
PremiumList pl =
|
||||||
|
savePremiumListAndEntries(
|
||||||
|
new PremiumList.Builder().setName("pl").build(), ImmutableList.of("test,USD 1"));
|
||||||
|
Map<String, PremiumListEntry> entries = loadPremiumListEntries(pl);
|
||||||
|
assertThat(entries.keySet()).containsExactly("test");
|
||||||
|
assertThat(loadPremiumListEntries(PremiumList.get("pl").get())).isEqualTo(entries);
|
||||||
|
// Save again with no changes, and clear the cache to force a re-load from Datastore.
|
||||||
|
PremiumList resaved = savePremiumListAndEntries(pl, ImmutableList.of("test,USD 1"));
|
||||||
|
ofy().clearSessionCache();
|
||||||
|
Map<String, PremiumListEntry> entriesReloaded =
|
||||||
|
loadPremiumListEntries(PremiumList.get("pl").get());
|
||||||
|
assertThat(entriesReloaded).hasSize(1);
|
||||||
|
assertThat(entriesReloaded).containsKey("test");
|
||||||
|
assertThat(entriesReloaded.get("test").parent).isEqualTo(resaved.getRevisionKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelete() throws Exception {
|
||||||
|
persistPremiumList("gtld1", "trombone,USD 10");
|
||||||
|
assertThat(PremiumList.get("gtld1")).isPresent();
|
||||||
|
Key<PremiumListRevision> parent = PremiumList.get("gtld1").get().getRevisionKey();
|
||||||
|
deletePremiumList(PremiumList.get("gtld1").get());
|
||||||
|
assertThat(PremiumList.get("gtld1")).isAbsent();
|
||||||
|
assertThat(ofy().load().type(PremiumListEntry.class).ancestor(parent).list()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelete_largeNumberOfEntries_succeeds() {
|
||||||
|
persistHumongousPremiumList("ginormous", 2500);
|
||||||
|
deletePremiumList(PremiumList.get("ginormous").get());
|
||||||
|
assertThat(PremiumList.get("ginormous")).isAbsent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelete_failsWhenListDoesntExist() throws Exception {
|
||||||
|
thrown.expect(IllegalStateException.class);
|
||||||
|
deletePremiumList(PremiumList.get("tld-premium-blah").get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Persists a premium list with a specified number of nonsense entries. */
|
||||||
|
private PremiumList persistHumongousPremiumList(String name, int size) {
|
||||||
|
String[] entries = new String[size];
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
entries[i] = String.format("%d,USD 100 # blahz", i);
|
||||||
|
}
|
||||||
|
return persistPremiumList(name, entries);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ import static google.registry.model.EppResourceUtils.createDomainRepoId;
|
||||||
import static google.registry.model.EppResourceUtils.createRepoId;
|
import static google.registry.model.EppResourceUtils.createRepoId;
|
||||||
import static google.registry.model.domain.launch.ApplicationStatus.VALIDATED;
|
import static google.registry.model.domain.launch.ApplicationStatus.VALIDATED;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.model.registry.label.PremiumList.parentEntriesOnRevision;
|
import static google.registry.model.registry.label.PremiumListUtils.parentPremiumListEntriesOnRevision;
|
||||||
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
|
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
|
||||||
import static google.registry.util.CollectionUtils.difference;
|
import static google.registry.util.CollectionUtils.difference;
|
||||||
import static google.registry.util.CollectionUtils.union;
|
import static google.registry.util.CollectionUtils.union;
|
||||||
|
@ -365,7 +365,7 @@ public class DatastoreHelper {
|
||||||
.now();
|
.now();
|
||||||
ofy()
|
ofy()
|
||||||
.saveWithoutBackup()
|
.saveWithoutBackup()
|
||||||
.entities(parentEntriesOnRevision(entries.values(), Key.create(revision)))
|
.entities(parentPremiumListEntriesOnRevision(entries.values(), Key.create(revision)))
|
||||||
.now();
|
.now();
|
||||||
return ofy().load().entity(premiumList).now();
|
return ofy().load().entity(premiumList).now();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.tools;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.loadPremiumListEntries;
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
||||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||||
|
@ -32,7 +33,7 @@ public class DeletePremiumListCommandTest extends CommandTestCase<DeletePremiumL
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess() throws Exception {
|
public void testSuccess() throws Exception {
|
||||||
PremiumList premiumList = persistPremiumList("xn--q9jyb4c", "blah,USD 100");
|
PremiumList premiumList = persistPremiumList("xn--q9jyb4c", "blah,USD 100");
|
||||||
assertThat(premiumList.loadPremiumListEntries()).hasSize(1);
|
assertThat(loadPremiumListEntries(premiumList)).hasSize(1);
|
||||||
runCommand("--force", "--name=xn--q9jyb4c");
|
runCommand("--force", "--name=xn--q9jyb4c");
|
||||||
assertThat(PremiumList.get("xn--q9jyb4c")).isAbsent();
|
assertThat(PremiumList.get("xn--q9jyb4c")).isAbsent();
|
||||||
|
|
||||||
|
@ -62,7 +63,8 @@ public class DeletePremiumListCommandTest extends CommandTestCase<DeletePremiumL
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
assertThat(PremiumList.get(premiumList.getName())).isPresent();
|
assertThat(PremiumList.get(premiumList.getName())).isPresent();
|
||||||
assertThat(e)
|
assertThat(e)
|
||||||
.hasMessage("Cannot delete premium list because it is used on these tld(s): xn--q9jyb4c");
|
.hasMessageThat()
|
||||||
|
.isEqualTo("Cannot delete premium list because it is used on these tld(s): xn--q9jyb4c");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
package google.registry.tools.server;
|
package google.registry.tools.server;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.model.registry.label.PremiumList.getPremiumPrice;
|
import static google.registry.model.registry.label.PremiumListUtils.deletePremiumList;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.loadPremiumListEntries;
|
||||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
|
@ -37,13 +39,8 @@ import org.junit.runners.JUnit4;
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class CreatePremiumListActionTest {
|
public class CreatePremiumListActionTest {
|
||||||
|
|
||||||
@Rule
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
@Rule public final ExceptionRule thrown = new ExceptionRule();
|
||||||
.withDatastore()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final ExceptionRule thrown = new ExceptionRule();
|
|
||||||
|
|
||||||
CreatePremiumListAction action;
|
CreatePremiumListAction action;
|
||||||
FakeJsonResponse response;
|
FakeJsonResponse response;
|
||||||
|
@ -51,7 +48,7 @@ public class CreatePremiumListActionTest {
|
||||||
@Before
|
@Before
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
createTlds("foo", "xn--q9jyb4c", "how");
|
createTlds("foo", "xn--q9jyb4c", "how");
|
||||||
PremiumList.get("foo").get().delete();
|
deletePremiumList(PremiumList.get("foo").get());
|
||||||
action = new CreatePremiumListAction();
|
action = new CreatePremiumListAction();
|
||||||
response = new FakeJsonResponse();
|
response = new FakeJsonResponse();
|
||||||
action.response = response;
|
action.response = response;
|
||||||
|
@ -83,7 +80,7 @@ public class CreatePremiumListActionTest {
|
||||||
action.override = true;
|
action.override = true;
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||||
assertThat(PremiumList.get("zanzibar").get().loadPremiumListEntries()).hasSize(1);
|
assertThat(loadPremiumListEntries(PremiumList.get("zanzibar").get())).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -92,7 +89,7 @@ public class CreatePremiumListActionTest {
|
||||||
action.inputData = "rich,USD 25\nricher,USD 1000\n";
|
action.inputData = "rich,USD 25\nricher,USD 1000\n";
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||||
assertThat(PremiumList.get("foo").get().loadPremiumListEntries()).hasSize(2);
|
assertThat(loadPremiumListEntries(PremiumList.get("foo").get())).hasSize(2);
|
||||||
assertThat(getPremiumPrice("rich", Registry.get("foo"))).hasValue(Money.parse("USD 25"));
|
assertThat(getPremiumPrice("rich", Registry.get("foo"))).hasValue(Money.parse("USD 25"));
|
||||||
assertThat(getPremiumPrice("diamond", Registry.get("foo"))).isAbsent();
|
assertThat(getPremiumPrice("diamond", Registry.get("foo"))).isAbsent();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
package google.registry.tools.server;
|
package google.registry.tools.server;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.model.registry.label.PremiumList.getPremiumPrice;
|
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
|
||||||
|
import static google.registry.model.registry.label.PremiumListUtils.loadPremiumListEntries;
|
||||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ public class UpdatePremiumListActionTest {
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||||
Registry registry = Registry.get("foo");
|
Registry registry = Registry.get("foo");
|
||||||
assertThat(PremiumList.get("foo").get().loadPremiumListEntries()).hasSize(3);
|
assertThat(loadPremiumListEntries(PremiumList.get("foo").get())).hasSize(3);
|
||||||
assertThat(getPremiumPrice("rich", registry)).hasValue(Money.parse("USD 75"));
|
assertThat(getPremiumPrice("rich", registry)).hasValue(Money.parse("USD 75"));
|
||||||
assertThat(getPremiumPrice("richer", registry)).hasValue(Money.parse("USD 5000"));
|
assertThat(getPremiumPrice("richer", registry)).hasValue(Money.parse("USD 5000"));
|
||||||
assertThat(getPremiumPrice("poor", registry)).hasValue(Money.parse("USD 0.99"));
|
assertThat(getPremiumPrice("poor", registry)).hasValue(Money.parse("USD 0.99"));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue