1
0
mirror of https://github.com/google/nomulus synced 2026-06-09 16:33:02 +00:00

Compare commits

...

4 Commits

Author SHA1 Message Date
sarahcaseybot d283cf1c90 Remove old DomainList fields from Registry (#1231)
* Remove old DomainList fields from Registry

I also resaved all Registry objects in sandbox and production to make sure that the new field is populated on all entity objects.

* small fixes

* Some more small fixes

* Delete commented out code

* Remove existence check in tests
2021-07-08 17:19:11 -04:00
Rachel Guan f5d344d5c9 Add cc support to email service (#1230)
* Add cc support to email service
2021-07-08 12:03:03 -04:00
Weimin Yu 61d029d955 Ensure VKey is actually serializable (#1235)
* Ensure VKey is actually serializable

Tighten field type so that non-serializable object cannot be set as
sqlKey.

This would make it easier to make EppResource entities Serializable in
the future.
2021-07-08 10:54:22 -04:00
Lai Jiang 2195ba90fa Add a method to set a "not in" WHERE clause in CriteriaQueryBuilder (#1225)
<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1225)
<!-- Reviewable:end -->
2021-07-07 15:49:29 -04:00
28 changed files with 242 additions and 201 deletions
@@ -113,7 +113,7 @@ public class ExportPremiumTermsAction implements Runnable {
"Skipping premium terms export for TLD %s because Drive folder isn't specified", tld);
return Optional.of("Skipping export because no Drive folder is associated with this TLD");
}
if (!registry.getPremiumList().isPresent()) {
if (!registry.getPremiumListName().isPresent()) {
logger.atInfo().log("No premium terms to export for TLD %s", tld);
return Optional.of("No premium lists configured");
}
@@ -137,8 +137,8 @@ public class ExportPremiumTermsAction implements Runnable {
}
private String getFormattedPremiumTerms(Registry registry) {
checkState(registry.getPremiumList().isPresent(), "%s does not have a premium list", tld);
String premiumListName = registry.getPremiumList().get().getName();
checkState(registry.getPremiumListName().isPresent(), "%s does not have a premium list", tld);
String premiumListName = registry.getPremiumListName().get();
checkState(
PremiumListDao.getLatestRevision(premiumListName).isPresent(),
"Could not load premium list for " + tld);
@@ -63,7 +63,7 @@ public class ExportReservedTermsAction implements Runnable {
try {
Registry registry = Registry.get(tld);
String resultMsg;
if (registry.getReservedLists().isEmpty() && isNullOrEmpty(registry.getDriveFolderId())) {
if (registry.getReservedListNames().isEmpty() && isNullOrEmpty(registry.getDriveFolderId())) {
resultMsg = "No reserved lists configured";
logger.atInfo().log("No reserved terms to export for TLD %s", tld);
} else if (registry.getDriveFolderId() == null) {
@@ -15,11 +15,11 @@
package google.registry.export;
import com.google.common.base.Joiner;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.registry.Registry;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import google.registry.model.registry.label.ReservedListDao;
import java.util.Set;
import java.util.TreeSet;
import javax.inject.Inject;
@@ -39,8 +39,13 @@ public final class ExportUtils {
public String exportReservedTerms(Registry registry) {
StringBuilder termsBuilder = new StringBuilder(reservedTermsExportDisclaimer).append("\n");
Set<String> reservedTerms = new TreeSet<>();
for (Key<ReservedList> key : registry.getReservedLists()) {
ReservedList reservedList = ReservedList.load(key).get();
for (String reservedListName : registry.getReservedListNames()) {
ReservedList reservedList =
ReservedListDao.getLatestRevision(reservedListName)
.orElseThrow(
() ->
new IllegalStateException(
String.format("Reserved list %s does not exist", reservedListName)));
if (reservedList.getShouldPublish()) {
for (ReservedListEntry entry : reservedList.getReservedListEntries().values()) {
reservedTerms.add(entry.getLabel());
@@ -39,9 +39,7 @@ public final class StaticPremiumListPricingEngine implements PremiumPricingEngin
String label = InternetDomainName.from(fullyQualifiedDomainName).parts().get(0);
Registry registry = Registry.get(checkNotNull(tld, "tld"));
Optional<Money> premiumPrice =
registry
.getPremiumList()
.flatMap(listKey -> PremiumListDao.getPremiumPrice(listKey.getName(), label));
registry.getPremiumListName().flatMap(pl -> PremiumListDao.getPremiumPrice(pl, label));
return DomainPrices.create(
premiumPrice.isPresent(),
premiumPrice.orElse(registry.getStandardCreateCost()),
@@ -47,7 +47,6 @@ import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Mapify;
import com.googlecode.objectify.annotation.OnLoad;
import com.googlecode.objectify.annotation.OnSave;
import com.googlecode.objectify.annotation.Parent;
import google.registry.model.Buildable;
@@ -112,26 +111,6 @@ public class Registry extends ImmutableObject implements Buildable, DatastoreAnd
@PostLoad
void postLoad() {
tldStr = tldStrId;
// TODO(sarahbot@): Remove the rest of this method after this data migration is complete
if (premiumListName != null) {
premiumList = Key.create(getCrossTldKey(), PremiumList.class, premiumListName);
}
if (reservedListNames != null) {
reservedLists =
reservedListNames.stream()
.map(name -> Key.create(getCrossTldKey(), ReservedList.class, name))
.collect(toImmutableSet());
}
}
// TODO(sarahbot@): Remove this method after this data migration is complete
@OnLoad
void onLoad() {
if (reservedLists != null) {
reservedListNames =
reservedLists.stream().map(key -> key.getName()).collect(toImmutableSet());
}
premiumListName = premiumList == null ? null : premiumList.getName();
}
/** The suffix that identifies roids as belonging to this specific tld, e.g. -HOW for .how. */
@@ -408,9 +387,6 @@ public class Registry extends ImmutableObject implements Buildable, DatastoreAnd
@Column(nullable = false)
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
/** The set of reserved lists that are applicable to this registry. */
@Transient Set<Key<ReservedList>> reservedLists;
/** The set of reserved list names that are applicable to this registry. */
@Column(name = "reserved_list_names")
Set<String> reservedListNames;
@@ -423,13 +399,10 @@ public class Registry extends ImmutableObject implements Buildable, DatastoreAnd
* for a registry, the database should be queried for the entity with this name that has the
* largest revision ID.
*/
public ImmutableSet<Key<ReservedList>> getReservedLists() {
return nullToEmptyImmutableCopy(reservedLists);
public ImmutableSet<String> getReservedListNames() {
return nullToEmptyImmutableCopy(reservedListNames);
}
/** The static {@link PremiumList} for this TLD, if there is one. */
@Transient Key<PremiumList> premiumList;
/**
* The name of the {@link PremiumList} for this TLD, if there is one.
*
@@ -647,8 +620,8 @@ public class Registry extends ImmutableObject implements Buildable, DatastoreAnd
return anchorTenantAddGracePeriodLength;
}
public Optional<Key<PremiumList>> getPremiumList() {
return Optional.ofNullable(premiumList);
public Optional<String> getPremiumListName() {
return Optional.ofNullable(premiumListName);
}
public CurrencyUnit getCurrency() {
@@ -919,26 +892,15 @@ public class Registry extends ImmutableObject implements Buildable, DatastoreAnd
public Builder setReservedLists(Set<ReservedList> reservedLists) {
checkArgumentNotNull(reservedLists, "reservedLists must not be null");
ImmutableSet.Builder<Key<ReservedList>> builder = new ImmutableSet.Builder<>();
ImmutableSet.Builder<String> nameBuilder = new ImmutableSet.Builder<>();
for (ReservedList reservedList : reservedLists) {
builder.add(Key.create(reservedList));
nameBuilder.add(reservedList.getName());
}
getInstance().reservedLists = builder.build();
getInstance().reservedListNames = nameBuilder.build();
return this;
}
public Builder setPremiumList(@Nullable PremiumList premiumList) {
getInstance().premiumList = (premiumList == null) ? null : Key.create(premiumList);
getInstance().premiumListName = (premiumList == null) ? null : premiumList.getName();
return this;
}
@VisibleForTesting
public Builder setPremiumListKey(@Nullable Key<PremiumList> premiumList) {
getInstance().premiumList = premiumList;
getInstance().premiumListName = (premiumList == null) ? null : premiumList.getName();
return this;
}
@@ -171,6 +171,7 @@ public abstract class BaseDomainLabelList<T extends Comparable<?>, R extends Dom
.collect(toImmutableSet());
}
// TODO(b/193043636): Refactor this class to no longer use key references
protected abstract boolean refersToKey(
Registry registry, Key<? extends BaseDomainLabelList<?, ?>> key);
@@ -283,7 +283,7 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
@Override
public boolean refersToKey(Registry registry, Key<? extends BaseDomainLabelList<?, ?>> key) {
return Objects.equals(registry.getPremiumList().orElse(null), key);
return Objects.equals(registry.getPremiumListName().orElse(null), key.getName());
}
@Override
@@ -20,7 +20,6 @@ import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
import static google.registry.model.ImmutableObject.Insignificant;
import static google.registry.model.registry.label.ReservationType.FULLY_BLOCKED;
import static google.registry.persistence.transaction.QueryComposer.Comparator.EQ;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
@@ -187,7 +186,7 @@ public final class ReservedList
@Override
protected boolean refersToKey(Registry registry, Key<? extends BaseDomainLabelList<?, ?>> key) {
return registry.getReservedLists().contains(key);
return registry.getReservedListNames().contains(key.getName());
}
/** Determines whether the ReservedList is in use on any Registry */
@@ -236,11 +235,6 @@ public final class ReservedList
return getFromCache(listName, cache);
}
/** Loads a ReservedList from its Objectify key. */
public static Optional<ReservedList> load(Key<ReservedList> key) {
return get(key.getName());
}
/**
* Queries the set of all reserved lists associated with the specified TLD and returns the
* reservation types of the label.
@@ -270,7 +264,7 @@ public final class ReservedList
new ImmutableSet.Builder<>();
// Loop through all reservation lists and add each of them.
for (ReservedList rl : loadReservedLists(registry.getReservedLists())) {
for (ReservedList rl : loadReservedLists(registry.getReservedListNames())) {
if (rl.getReservedListEntries().containsKey(label)) {
ReservedListEntry entry = rl.getReservedListEntries().get(label);
entriesBuilder.add(entry);
@@ -285,17 +279,15 @@ public final class ReservedList
}
private static ImmutableSet<ReservedList> loadReservedLists(
ImmutableSet<Key<ReservedList>> reservedListKeys) {
return reservedListKeys
.stream()
ImmutableSet<String> reservedListNames) {
return reservedListNames.stream()
.map(
(listKey) -> {
(listName) -> {
try {
return cache.get(listKey.getName());
return cache.get(listName);
} catch (ExecutionException e) {
throw new UncheckedExecutionException(
String.format(
"Could not load the reserved list '%s' from the cache", listKey.getName()),
String.format("Could not load the reserved list '%s' from the cache", listName),
e);
}
})
@@ -21,6 +21,7 @@ import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.domain.DomainBase;
import google.registry.model.reporting.HistoryEntry;
import java.io.Serializable;
import javax.annotation.Nullable;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
@@ -46,7 +47,7 @@ public abstract class BillingVKey<K> extends EppHistoryVKey<K, DomainBase> {
}
@Override
public Object createSqlKey() {
public Serializable createSqlKey() {
return billingId;
}
@@ -21,6 +21,7 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.DomainHistory.DomainHistoryId;
import google.registry.model.reporting.HistoryEntry;
import java.io.Serializable;
import javax.persistence.Embeddable;
/** {@link VKey} for {@link HistoryEntry} which parent is {@link DomainBase}. */
@@ -35,7 +36,7 @@ public class DomainHistoryVKey extends EppHistoryVKey<HistoryEntry, DomainBase>
}
@Override
public Object createSqlKey() {
public Serializable createSqlKey() {
return new DomainHistoryId(repoId, historyRevisionId);
}
@@ -101,7 +101,7 @@ public abstract class EppHistoryVKey<K, E extends EppResource> extends Immutable
return VKey.create(vKeyType, createSqlKey(), createOfyKey());
}
public abstract Object createSqlKey();
public abstract Serializable createSqlKey();
public abstract Key<K> createOfyKey();
}
@@ -37,7 +37,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
private static final long serialVersionUID = -5291472863840231240L;
// The SQL key for the referenced entity.
Object sqlKey;
Serializable sqlKey;
// The objectify key for the referenced entity.
Key<T> ofyKey;
@@ -46,7 +46,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
VKey() {}
VKey(Class<? extends T> kind, Key<T> ofyKey, Object sqlKey) {
VKey(Class<? extends T> kind, Key<T> ofyKey, Serializable sqlKey) {
this.kind = kind;
this.ofyKey = ofyKey;
this.sqlKey = sqlKey;
@@ -57,7 +57,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
*
* <p>Deprecated. Create symmetric keys with create() instead.
*/
public static <T> VKey<T> createSql(Class<T> kind, Object sqlKey) {
public static <T> VKey<T> createSql(Class<T> kind, Serializable sqlKey) {
checkArgumentNotNull(kind, "kind must not be null");
checkArgumentNotNull(sqlKey, "sqlKey must not be null");
return new VKey<T>(kind, null, sqlKey);
@@ -71,7 +71,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
}
/** Creates a {@link VKey} which only contains both sql and ofy primary key. */
public static <T> VKey<T> create(Class<T> kind, Object sqlKey, Key<T> ofyKey) {
public static <T> VKey<T> create(Class<T> kind, Serializable sqlKey, Key<T> ofyKey) {
checkArgumentNotNull(kind, "kind must not be null");
checkArgumentNotNull(sqlKey, "sqlKey must not be null");
checkArgumentNotNull(ofyKey, "ofyKey must not be null");
@@ -84,8 +84,8 @@ public class VKey<T> extends ImmutableObject implements Serializable {
* <p>IMPORTANT USAGE NOTE: Datastore entities that are not roots of entity groups (i.e. those
* that do not have a null parent in their Objectify keys) require the full entity group
* inheritance chain to be specified and thus cannot use this create method. You need to use
* {@link #create(Class, Object, Key)} instead and pass in the full, valid parent field in the
* Datastore key.
* {@link #create(Class, Serializable, Key)} instead and pass in the full, valid parent field in
* the Datastore key.
*/
public static <T> VKey<T> create(Class<T> kind, long id) {
checkArgument(
@@ -102,8 +102,8 @@ public class VKey<T> extends ImmutableObject implements Serializable {
* <p>IMPORTANT USAGE NOTE: Datastore entities that are not roots of entity groups (i.e. those
* that do not have a null parent in their Objectify keys) require the full entity group
* inheritance chain to be specified and thus cannot use this create method. You need to use
* {@link #create(Class, Object, Key)} instead and pass in the full, valid parent field in the
* Datastore key.
* {@link #create(Class, Serializable, Key)} instead and pass in the full, valid parent field in
* the Datastore key.
*/
public static <T> VKey<T> create(Class<T> kind, String name) {
checkArgument(
@@ -172,7 +172,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
throw new IllegalArgumentException("Missing value for last key of type " + lastClass);
}
Object sqlKey = getSqlKey();
Serializable sqlKey = getSqlKey();
Key<T> ofyKey =
sqlKey instanceof Long
? Key.create(lastKey, getKind(), (Long) sqlKey)
@@ -197,7 +197,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
}
/** Returns the SQL primary key. */
public Object getSqlKey() {
public Serializable getSqlKey() {
checkState(sqlKey != null, "Attempting obtain a null SQL key.");
return this.sqlKey;
}
@@ -16,11 +16,13 @@ package google.registry.persistence.converter;
import com.googlecode.objectify.Key;
import google.registry.persistence.VKey;
import java.io.Serializable;
import javax.annotation.Nullable;
import javax.persistence.AttributeConverter;
/** Converts VKey to a string column. */
public abstract class VKeyConverter<T, C> implements AttributeConverter<VKey<? extends T>, C> {
public abstract class VKeyConverter<T, C extends Serializable>
implements AttributeConverter<VKey<? extends T>, C> {
@Override
@Nullable
public C convertToDatabaseColumn(@Nullable VKey<? extends T> attribute) {
@@ -62,6 +62,13 @@ public class CriteriaQueryBuilder<T> {
return where(root.get(fieldName).in(values));
}
/**
* Adds a WHERE clause to the query specifying that a value must not be in the given collection.
*/
public CriteriaQueryBuilder<T> whereFieldIsNotIn(String fieldName, Collection<?> values) {
return where(root.get(fieldName).in(values).not());
}
/**
* Adds a WHERE clause to the query specifying that a collection field must contain a particular
* value.
@@ -46,6 +46,7 @@ import google.registry.schema.replay.SqlOnlyEntity;
import google.registry.util.Clock;
import google.registry.util.Retrier;
import google.registry.util.SystemSleeper;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Calendar;
@@ -489,7 +490,8 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
loadByKey(
VKey.createSql(
possibleChild.getClass(),
emf.getPersistenceUnitUtil().getIdentifier(possibleChild)));
// Casting to Serializable is safe according to JPA (JSR 338 sec. 2.4).
(Serializable) emf.getPersistenceUnitUtil().getIdentifier(possibleChild)));
return returnValue;
}
@@ -15,7 +15,6 @@
package google.registry.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.intersection;
import static com.google.common.collect.Sets.union;
@@ -26,7 +25,6 @@ import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.googlecode.objectify.Key;
import google.registry.config.RegistryEnvironment;
import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState;
@@ -113,7 +111,7 @@ class UpdateTldCommand extends CreateOrUpdateTldCommand {
ImmutableSet<String> getReservedLists(Registry oldRegistry) {
return formUpdatedList(
"reserved lists",
oldRegistry.getReservedLists().stream().map(Key::getName).collect(toImmutableSet()),
oldRegistry.getReservedListNames(),
reservedListNames,
reservedListsAdd,
reservedListsRemove);
@@ -70,8 +70,7 @@ public final class OteAccountBuilderTest {
private void assertTldExists(String tld, TldState tldState, Money eapFee) {
Registry registry = Registry.get(tld);
assertThat(registry).isNotNull();
assertThat(registry.getPremiumList()).isPresent();
assertThat(registry.getPremiumList().get().getName()).isEqualTo("default_sandbox_list");
assertThat(registry.getPremiumListName()).hasValue("default_sandbox_list");
assertThat(registry.getTldStateTransitions()).containsExactly(START_OF_TIME, tldState);
assertThat(registry.getDnsWriters()).containsExactly("VoidDnsWriter");
assertThat(registry.getAddGracePeriodLength()).isEqualTo(Duration.standardHours(1));
@@ -36,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.googlecode.objectify.Key;
import google.registry.dns.writer.VoidDnsWriter;
import google.registry.model.EntityTestCase;
import google.registry.model.registry.Registry.RegistryNotFoundException;
@@ -162,18 +161,18 @@ public final class RegistryTest extends EntityTestCase {
.asBuilder()
.setReservedLists(ImmutableSet.of(rl15))
.build();
assertThat(registry1.getReservedLists()).hasSize(1);
assertThat(registry1.getReservedListNames()).hasSize(1);
Registry registry2 =
registry1.asBuilder().setReservedLists(ImmutableSet.of(rl15, rl16)).build();
assertThat(registry1.getReservedLists()).hasSize(1);
assertThat(registry2.getReservedLists()).hasSize(2);
assertThat(registry1.getReservedListNames()).hasSize(1);
assertThat(registry2.getReservedListNames()).hasSize(2);
}
@TestOfyAndSql
void testGetReservedLists_doesntReturnNullWhenUninitialized() {
Registry registry = newRegistry("foo", "FOO");
assertThat(registry.getReservedLists()).isNotNull();
assertThat(registry.getReservedLists()).isEmpty();
assertThat(registry.getReservedListNames()).isNotNull();
assertThat(registry.getReservedListNames()).isEmpty();
}
@TestOfyAndSql
@@ -211,10 +210,9 @@ public final class RegistryTest extends EntityTestCase {
.build());
Registry r =
Registry.get("tld").asBuilder().setReservedLists(ImmutableSet.of(rl5, rl6)).build();
assertThat(r.getReservedLists().stream().map(Key::getName))
.containsExactly("tld-reserved5", "tld-reserved6");
assertThat(r.getReservedListNames()).containsExactly("tld-reserved5", "tld-reserved6");
r = Registry.get("tld").asBuilder().setReservedLists(ImmutableSet.of()).build();
assertThat(r.getReservedLists()).isEmpty();
assertThat(r.getReservedListNames()).isEmpty();
}
@TestOfyAndSql
@@ -240,19 +238,18 @@ public final class RegistryTest extends EntityTestCase {
.asBuilder()
.setReservedListsByName(ImmutableSet.of("tld-reserved15", "tld-reserved16"))
.build();
assertThat(r.getReservedLists().stream().map(Key::getName))
.containsExactly("tld-reserved15", "tld-reserved16");
assertThat(r.getReservedListNames()).containsExactly("tld-reserved15", "tld-reserved16");
r = Registry.get("tld").asBuilder().setReservedListsByName(ImmutableSet.of()).build();
assertThat(r.getReservedLists()).isEmpty();
assertThat(r.getReservedListNames()).isEmpty();
}
@TestOfyAndSql
void testSetPremiumList() {
PremiumList pl2 = persistPremiumList("tld2", "lol,USD 50", "cat,USD 700");
Registry registry = Registry.get("tld").asBuilder().setPremiumList(pl2).build();
Optional<Key<PremiumList>> plKey = registry.getPremiumList();
assertThat(plKey).isPresent();
PremiumList stored = PremiumListDao.getLatestRevision(plKey.get().getName()).get();
Optional<String> pl = registry.getPremiumListName();
assertThat(pl).hasValue("tld2");
PremiumList stored = PremiumListDao.getLatestRevision(pl.get()).get();
assertThat(stored.getName()).isEqualTo("tld2");
}
@@ -86,7 +86,7 @@ class ReservedListTest {
@Test
void testGetReservationTypes_allLabelsAreUnreserved_withNoReservedLists() {
assertThat(Registry.get("tld").getReservedLists()).isEmpty();
assertThat(Registry.get("tld").getReservedListNames()).isEmpty();
assertThat(getReservationTypes("doodle", "tld")).isEmpty();
assertThat(getReservationTypes("access", "tld")).isEmpty();
assertThat(getReservationTypes("rich", "tld")).isEmpty();
@@ -152,6 +152,21 @@ class CriteriaQueryBuilderTest {
assertThat(result).containsExactly(entity3).inOrder();
}
@Test
void testSuccess_where_not_in_twoResults() {
List<CriteriaQueryBuilderTestEntity> result =
jpaTm()
.transact(
() -> {
CriteriaQuery<CriteriaQueryBuilderTestEntity> query =
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
.whereFieldIsNotIn("data", ImmutableList.of("aaa", "bbb"))
.build();
return jpaTm().query(query).getResultList();
});
assertThat(result).containsExactly(entity1, entity2).inOrder();
}
@Test
void testSuccess_where_in_twoResults() {
List<CriteriaQueryBuilderTestEntity> result =
@@ -16,7 +16,6 @@ package google.registry.schema.tld;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.testing.DatabaseHelper.newRegistry;
@@ -27,7 +26,6 @@ import static org.joda.time.Duration.standardDays;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.Key;
import google.registry.model.registry.label.PremiumList;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
@@ -203,22 +201,16 @@ public class PremiumListDaoTest {
@Test
void getPremiumPrice_worksSuccessfully() {
PremiumList premiumList =
PremiumListDao.save(
new PremiumList.Builder()
.setName("premlist")
.setCurrency(USD)
.setLabelsToPrices(TEST_PRICES)
.setCreationTime(fakeClock.nowUtc())
.build());
persistResource(
newRegistry("foobar", "FOOBAR")
.asBuilder()
.setPremiumListKey(
Key.create(
getCrossTldKey(),
google.registry.model.registry.label.PremiumList.class,
"premlist"))
.build());
PremiumListDao.save(
new PremiumList.Builder()
.setName("premlist")
.setCurrency(USD)
.setLabelsToPrices(TEST_PRICES)
.setCreationTime(fakeClock.nowUtc())
.build());
newRegistry("foobar", "FOOBAR").asBuilder().setPremiumList(premiumList).build());
assertThat(PremiumListDao.getPremiumPrice("premlist", "silver")).hasValue(Money.of(USD, 10.23));
assertThat(PremiumListDao.getPremiumPrice("premlist", "gold")).hasValue(Money.of(USD, 1305.47));
assertThat(PremiumListDao.getPremiumPrice("premlist", "zirconium")).isEmpty();
@@ -226,29 +218,23 @@ public class PremiumListDaoTest {
@Test
void testGetPremiumPrice_worksForJPY() {
PremiumList premiumList =
PremiumListDao.save(
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());
persistResource(
newRegistry("foobar", "FOOBAR")
.asBuilder()
.setPremiumListKey(
Key.create(
getCrossTldKey(),
google.registry.model.registry.label.PremiumList.class,
"premlist"))
.build());
PremiumListDao.save(
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());
newRegistry("foobar", "FOOBAR").asBuilder().setPremiumList(premiumList).build());
assertThat(PremiumListDao.getPremiumPrice("premlist", "silver")).hasValue(moneyOf(JPY, 10));
assertThat(PremiumListDao.getPremiumPrice("premlist", "gold")).hasValue(moneyOf(JPY, 1000));
assertThat(PremiumListDao.getPremiumPrice("premlist", "palladium"))
@@ -32,7 +32,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Range;
import com.googlecode.objectify.Key;
import google.registry.model.registry.Registry;
import java.math.BigDecimal;
import org.joda.money.Money;
@@ -279,7 +278,7 @@ class CreateTldCommandTest extends CommandTestCase<CreateTldCommand> {
"--roid_suffix=Q9JYB4C",
"--dns_writers=VoidDnsWriter",
"xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getReservedLists().stream().map(Key::getName))
assertThat(Registry.get("xn--q9jyb4c").getReservedListNames())
.containsExactly("xn--q9jyb4c_abuse", "common_abuse");
}
@@ -519,9 +518,7 @@ class CreateTldCommandTest extends CommandTestCase<CreateTldCommand> {
"--roid_suffix=Q9JYB4C",
"--dns_writers=FooDnsWriter",
"xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getPremiumList()).isPresent();
assertThat(Registry.get("xn--q9jyb4c").getPremiumList().get().getName())
.isEqualTo("xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getPremiumListName()).hasValue("xn--q9jyb4c");
}
@Test
@@ -72,8 +72,7 @@ class SetupOteCommandTest extends CommandTestCase<SetupOteCommand> {
assertThat(registry.getRoidSuffix()).isEqualTo(roidSuffix);
assertThat(registry.getTldState(DateTime.now(UTC))).isEqualTo(tldState);
assertThat(registry.getDnsWriters()).containsExactly("VoidDnsWriter");
assertThat(registry.getPremiumList()).isNotNull();
assertThat(registry.getPremiumList().get().getName()).isEqualTo("default_sandbox_list");
assertThat(registry.getPremiumListName()).hasValue("default_sandbox_list");
assertThat(registry.getAddGracePeriodLength()).isEqualTo(Duration.standardMinutes(60));
assertThat(registry.getRedemptionGracePeriodLength()).isEqualTo(Duration.standardMinutes(10));
assertThat(registry.getPendingDeleteLength()).isEqualTo(Duration.standardMinutes(5));
@@ -35,9 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.googlecode.objectify.Key;
import google.registry.model.registry.Registry;
import google.registry.model.registry.label.PremiumList;
import java.util.Optional;
import org.joda.money.Money;
import org.joda.time.DateTime;
@@ -254,7 +252,7 @@ class UpdateTldCommandTest extends CommandTestCase<UpdateTldCommand> {
void testSuccess_setReservedLists() throws Exception {
runCommandForced("--reserved_lists=xn--q9jyb4c_r1,xn--q9jyb4c_r2", "xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getReservedLists().stream().map(Key::getName))
assertThat(Registry.get("xn--q9jyb4c").getReservedListNames())
.containsExactly("xn--q9jyb4c_r1", "xn--q9jyb4c_r2");
}
@@ -264,7 +262,7 @@ class UpdateTldCommandTest extends CommandTestCase<UpdateTldCommand> {
.setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2"))
.build());
runCommandForced("--reserved_lists=xn--q9jyb4c_r2", "xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getReservedLists().stream().map(Key::getName))
assertThat(Registry.get("xn--q9jyb4c").getReservedListNames())
.containsExactly("xn--q9jyb4c_r2");
}
@@ -274,7 +272,7 @@ class UpdateTldCommandTest extends CommandTestCase<UpdateTldCommand> {
.setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1"))
.build());
runCommandForced("--add_reserved_lists=xn--q9jyb4c_r2", "xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getReservedLists().stream().map(Key::getName))
assertThat(Registry.get("xn--q9jyb4c").getReservedListNames())
.containsExactly("xn--q9jyb4c_r1", "xn--q9jyb4c_r2");
}
@@ -284,7 +282,7 @@ class UpdateTldCommandTest extends CommandTestCase<UpdateTldCommand> {
.setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2"))
.build());
runCommandForced("--remove_reserved_lists=xn--q9jyb4c_r1,xn--q9jyb4c_r2", "xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getReservedLists()).isEmpty();
assertThat(Registry.get("xn--q9jyb4c").getReservedListNames()).isEmpty();
}
@Test
@@ -293,7 +291,7 @@ class UpdateTldCommandTest extends CommandTestCase<UpdateTldCommand> {
.setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2"))
.build());
runCommandForced("--remove_reserved_lists=xn--q9jyb4c_r1", "xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getReservedLists().stream().map(Key::getName))
assertThat(Registry.get("xn--q9jyb4c").getReservedListNames())
.containsExactly("xn--q9jyb4c_r2");
}
@@ -839,21 +837,20 @@ class UpdateTldCommandTest extends CommandTestCase<UpdateTldCommand> {
@Test
void testSuccess_removePremiumListWithNull() throws Exception {
runCommandForced("--premium_list=null", "xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getPremiumList()).isEmpty();
assertThat(Registry.get("xn--q9jyb4c").getPremiumListName()).isEmpty();
}
@Test
void testSuccess_removePremiumListWithBlank() throws Exception {
runCommandForced("--premium_list=", "xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getPremiumList()).isEmpty();
assertThat(Registry.get("xn--q9jyb4c").getPremiumListName()).isEmpty();
}
@Test
void testSuccess_premiumListNotRemovedWhenNotSpecified() throws Exception {
runCommandForced("--add_reserved_lists=xn--q9jyb4c_r1,xn--q9jyb4c_r2", "xn--q9jyb4c");
Optional<Key<PremiumList>> premiumListKey = Registry.get("xn--q9jyb4c").getPremiumList();
assertThat(premiumListKey).isPresent();
assertThat(premiumListKey.get().getName()).isEqualTo("xn--q9jyb4c");
Optional<String> premiumListName = Registry.get("xn--q9jyb4c").getPremiumListName();
assertThat(premiumListName).hasValue("xn--q9jyb4c");
}
@Test
@@ -921,9 +918,7 @@ class UpdateTldCommandTest extends CommandTestCase<UpdateTldCommand> {
@Test
void testSuccess_setPremiumList() throws Exception {
runCommandForced("--premium_list=xn--q9jyb4c", "xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getPremiumList()).isPresent();
assertThat(Registry.get("xn--q9jyb4c").getPremiumList().get().getName())
.isEqualTo("xn--q9jyb4c");
assertThat(Registry.get("xn--q9jyb4c").getPremiumListName()).hasValue("xn--q9jyb4c");
}
@Test
@@ -658,7 +658,6 @@ class google.registry.model.registry.Registry {
boolean dnsPaused;
boolean escrowEnabled;
boolean invoicingEnabled;
com.googlecode.objectify.Key<google.registry.model.registry.label.PremiumList> premiumList;
google.registry.model.CreateAutoTimestamp creationTime;
google.registry.model.common.TimedTransitionProperty<google.registry.model.registry.Registry$TldState, google.registry.model.registry.Registry$TldStateTransition> tldStateTransitions;
google.registry.model.common.TimedTransitionProperty<org.joda.money.Money, google.registry.model.registry.Registry$BillingCostTransition> eapFeeSchedule;
@@ -672,7 +671,6 @@ class google.registry.model.registry.Registry {
java.lang.String roidSuffix;
java.lang.String tldStr;
java.lang.String tldUnicode;
java.util.Set<com.googlecode.objectify.Key<google.registry.model.registry.label.ReservedList>> reservedLists;
java.util.Set<java.lang.String> allowedFullyQualifiedHostNames;
java.util.Set<java.lang.String> allowedRegistrantContactIds;
java.util.Set<java.lang.String> dnsWriters;
@@ -26,16 +26,6 @@ import javax.mail.internet.InternetAddress;
@AutoValue
public abstract class EmailMessage {
public abstract String subject();
public abstract String body();
public abstract ImmutableSet<InternetAddress> recipients();
public abstract InternetAddress from();
public abstract ImmutableSet<InternetAddress> bccs();
public abstract Optional<MediaType> contentType();
public abstract Optional<Attachment> attachment();
public static Builder newBuilder() {
return new AutoValue_EmailMessage.Builder();
}
@@ -50,24 +40,48 @@ public abstract class EmailMessage {
.build();
}
public abstract String subject();
public abstract String body();
public abstract ImmutableSet<InternetAddress> recipients();
public abstract InternetAddress from();
public abstract ImmutableSet<InternetAddress> ccs();
public abstract ImmutableSet<InternetAddress> bccs();
public abstract Optional<MediaType> contentType();
public abstract Optional<Attachment> attachment();
/** Builder for {@link EmailMessage}. */
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setSubject(String subject);
public abstract Builder setBody(String body);
public abstract Builder setRecipients(Collection<InternetAddress> recipients);
public abstract Builder setFrom(InternetAddress from);
public abstract Builder setBccs(Collection<InternetAddress> bccs);
public abstract Builder setCcs(Collection<InternetAddress> ccs);
public abstract Builder setContentType(MediaType contentType);
public abstract Builder setAttachment(Attachment attachment);
abstract ImmutableSet.Builder<InternetAddress> recipientsBuilder();
abstract ImmutableSet.Builder<InternetAddress> bccsBuilder();
abstract ImmutableSet.Builder<InternetAddress> ccsBuilder();
public Builder addRecipient(InternetAddress value) {
recipientsBuilder().add(value);
return this;
@@ -78,28 +92,36 @@ public abstract class EmailMessage {
return this;
}
public Builder addCc(InternetAddress cc) {
ccsBuilder().add(cc);
return this;
}
public abstract EmailMessage build();
}
/** An attachment to the email, if one exists. */
@AutoValue
public abstract static class Attachment {
public abstract MediaType contentType();
public abstract String filename();
public abstract String content();
public static Builder newBuilder() {
return new AutoValue_EmailMessage_Attachment.Builder();
}
public abstract MediaType contentType();
public abstract String filename();
public abstract String content();
/** Builder for {@link Attachment}. */
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setContentType(MediaType contentType);
public abstract Builder setFilename(String filename);
public abstract Builder setContent(String content);
public abstract Attachment build();
}
}
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.util.Properties;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
@@ -50,8 +51,8 @@ public class SendEmailService {
}
/**
* Converts the provided message content into a {@link javax.mail.Message} and sends it with
* retry on transient failures.
* Converts the provided message content into a {@link javax.mail.Message} and sends it with retry
* on transient failures.
*/
public void sendEmail(EmailMessage emailMessage) {
retrier.callWithRetry(
@@ -78,9 +79,8 @@ public class SendEmailService {
attachmentPart.setFileName(attachment.filename());
multipart.addBodyPart(attachmentPart);
}
for (InternetAddress bcc : emailMessage.bccs()) {
msg.addRecipient(RecipientType.BCC, bcc);
}
msg.addRecipients(RecipientType.BCC, toArray(emailMessage.bccs(), Address.class));
msg.addRecipients(RecipientType.CC, toArray(emailMessage.ccs(), Address.class));
msg.setContent(multipart);
msg.saveChanges();
transportEmailSender.sendMessage(msg);
@@ -68,7 +68,28 @@ class SendEmailServiceTest {
}
@Test
void testSuccess_bcc() throws Exception {
void testSuccess_addBccs() throws Exception {
EmailMessage.Builder contentBuilder =
EmailMessage.newBuilder()
.setFrom(new InternetAddress("test@example.com"))
.setSubject("test subject")
.setBody("test body");
for (String email :
ImmutableList.of("bcc@example.com", "bcc1@example.com", "bcc2@example.com")) {
contentBuilder.addBcc(new InternetAddress(email));
}
sendEmailService.sendEmail(contentBuilder.build());
assertThat(getMessage().getRecipients(RecipientType.BCC))
.asList()
.containsExactly(
new InternetAddress("bcc@example.com"),
new InternetAddress("bcc1@example.com"),
new InternetAddress("bcc2@example.com"));
}
@Test
void testSuccess_setBccs() throws Exception {
EmailMessage content =
createBuilder()
.setBccs(
@@ -77,19 +98,63 @@ class SendEmailServiceTest {
new InternetAddress("bcc2@example.com")))
.build();
sendEmailService.sendEmail(content);
Message message = getMessage();
assertThat(message.getRecipients(RecipientType.BCC))
assertThat(getMessage().getRecipients(RecipientType.BCC))
.asList()
.containsExactly(
new InternetAddress("bcc@example.com"), new InternetAddress("bcc2@example.com"));
}
@Test
void testSuccess_contentType() throws Exception {
EmailMessage content = createBuilder().setContentType(MediaType.HTML_UTF_8).build();
void testSuccess_emptyBcc() throws Exception {
sendEmailService.sendEmail(createBuilder().setBccs(ImmutableList.of()).build());
assertThat(getMessage().getRecipients(RecipientType.BCC)).isNull();
}
@Test
void testSuccess_addCcs() throws Exception {
EmailMessage.Builder contentBuilder = EmailMessage.newBuilder();
contentBuilder
.setFrom(new InternetAddress("test@example.com"))
.setSubject("test subject")
.setBody("test body");
for (String email : ImmutableList.of("cc@example.com", "cc1@example.com", "cc2@example.com")) {
contentBuilder.addCc(new InternetAddress(email));
}
sendEmailService.sendEmail(contentBuilder.build());
assertThat(getMessage().getRecipients(RecipientType.CC))
.asList()
.containsExactly(
new InternetAddress("cc@example.com"),
new InternetAddress("cc1@example.com"),
new InternetAddress("cc2@example.com"));
}
@Test
void testSuccess_setCcs() throws Exception {
EmailMessage content =
createBuilder()
.setCcs(
ImmutableList.of(
new InternetAddress("cc@example.com"), new InternetAddress("cc2@example.com")))
.build();
sendEmailService.sendEmail(content);
Message message = getMessage();
assertThat(getInternalContent(message).getContentType()).isEqualTo("text/html; charset=utf-8");
assertThat(getMessage().getRecipients(RecipientType.CC))
.asList()
.containsExactly(
new InternetAddress("cc@example.com"), new InternetAddress("cc2@example.com"));
}
@Test
void testSuccess_emptyCC() throws Exception {
sendEmailService.sendEmail(createBuilder().setCcs(ImmutableList.of()).build());
assertThat(getMessage().getRecipients(RecipientType.CC)).isNull();
}
@Test
void testSuccess_contentType() throws Exception {
sendEmailService.sendEmail(createBuilder().setContentType(MediaType.HTML_UTF_8).build());
assertThat(getInternalContent(getMessage()).getContentType())
.isEqualTo("text/html; charset=utf-8");
}
@Test
@@ -117,17 +182,16 @@ class SendEmailServiceTest {
.doNothing()
.when(wrapper)
.sendMessage(messageCaptor.capture());
EmailMessage content = createBuilder().build();
sendEmailService.sendEmail(content);
sendEmailService.sendEmail(createBuilder().build());
assertThat(messageCaptor.getValue().getSubject()).isEqualTo("Subject");
}
@Test
void testFailure_wrongExceptionType() throws Exception {
doThrow(new RuntimeException("this is a runtime exception")).when(wrapper).sendMessage(any());
EmailMessage content = createBuilder().build();
RuntimeException thrown =
assertThrows(RuntimeException.class, () -> sendEmailService.sendEmail(content));
assertThrows(
RuntimeException.class, () -> sendEmailService.sendEmail(createBuilder().build()));
assertThat(thrown).hasMessageThat().isEqualTo("this is a runtime exception");
}
@@ -137,9 +201,9 @@ class SendEmailServiceTest {
.doThrow(new MessagingException("second"))
.when(wrapper)
.sendMessage(any());
EmailMessage content = createBuilder().build();
RuntimeException thrown =
assertThrows(RuntimeException.class, () -> sendEmailService.sendEmail(content));
assertThrows(
RuntimeException.class, () -> sendEmailService.sendEmail(createBuilder().build()));
assertThat(thrown).hasCauseThat().hasMessageThat().isEqualTo("second");
assertThat(thrown).hasCauseThat().isInstanceOf(MessagingException.class);
}