mirror of
https://github.com/google/nomulus.git
synced 2025-04-29 19:47:51 +02:00
Add SQL searching to RdapEntitySearchAction and RdapSearchActionBase (#969)
- Adds a CriteriaQueryBuilder class that allows us to build CriteriaQuery objects with sane and modular WHERE and ORDER BY clauses. CriteriaQuery requires that all WHERE and ORDER BY clauses be specified at the same time (else later ones will overwrite the earlier ones) so in order to have a proper builder pattern we need to wait to build the query object until we are done adding clauses. - In addition, encapsulating the query logic in the CriteriaQueryBuilder class means that we don't need to deal with the complicated Root/Path branching, otherwise we'd have to keep track of CriteriaQuery and Root objects everywhere. - Added a REPLAYED_ENTITIES TransitionId that will represent all replayed entities, e.g. EppResources. Also sets this, by default, to always be CLOUD_SQL if we're using the SQL transaction manager in tests. - Added branching logic in RdapEntitySearchAction based on that transition ID that determines whether we do the existing ofy query logic or JPA logic.
This commit is contained in:
parent
519cbfb660
commit
f78b64d93c
9 changed files with 681 additions and 139 deletions
|
@ -207,6 +207,9 @@ PRESUBMITS = {
|
|||
"ForeignKeyIndex.java",
|
||||
"HistoryEntryDao.java",
|
||||
"JpaTransactionManagerImpl.java",
|
||||
# CriteriaQueryBuilder is a false positive
|
||||
"CriteriaQueryBuilder.java",
|
||||
"RdapSearchActionBase.java",
|
||||
},
|
||||
):
|
||||
"The first String parameter to EntityManager.create(Native)Query "
|
||||
|
|
|
@ -62,6 +62,8 @@ public class DatabaseTransitionSchedule extends ImmutableObject implements Datas
|
|||
DOMAIN_LABEL_LISTS,
|
||||
/** The schedule for the migration of the {@link SignedMarkRevocationList} entity. */
|
||||
SIGNED_MARK_REVOCATION_LIST,
|
||||
/** The schedule for all asynchronously-replayed entities, ones not dually-written. */
|
||||
REPLAYED_ENTITIES,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright 2021 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.persistence.transaction;
|
||||
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.Collection;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Order;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
/**
|
||||
* An extension of {@link CriteriaQuery} that uses a Builder-style pattern when adding "WHERE"
|
||||
* and/or "ORDER BY" clauses.
|
||||
*
|
||||
* <p>{@link CriteriaQuery}, as is, requires that all clauses must be passed in at once -- if one
|
||||
* calls "WHERE" multiple times, the later call overwrites the earlier call.
|
||||
*/
|
||||
public class CriteriaQueryBuilder<T> {
|
||||
|
||||
/** Functional interface that defines the 'where' operator, e.g. {@link CriteriaBuilder#equal}. */
|
||||
public interface WhereClause<U> {
|
||||
Predicate predicate(Expression<U> expression, U object);
|
||||
}
|
||||
|
||||
/** Functional interface that defines the order-by operator, e.g. {@link CriteriaBuilder#asc}. */
|
||||
public interface OrderByClause<U> {
|
||||
Order order(Expression<U> expression);
|
||||
}
|
||||
|
||||
private final CriteriaQuery<T> query;
|
||||
private final Root<T> root;
|
||||
private final ImmutableList.Builder<Predicate> predicates = new ImmutableList.Builder<>();
|
||||
private final ImmutableList.Builder<Order> orders = new ImmutableList.Builder<>();
|
||||
|
||||
private CriteriaQueryBuilder(CriteriaQuery<T> query, Root<T> root) {
|
||||
this.query = query;
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/** Adds a WHERE clause to the query, given the specified operation, field, and value. */
|
||||
public <V> CriteriaQueryBuilder<T> where(WhereClause<V> whereClause, String fieldName, V value) {
|
||||
Expression<V> expression = root.get(fieldName);
|
||||
return where(whereClause.predicate(expression, value));
|
||||
}
|
||||
|
||||
/** Adds a WHERE clause to the query specifying that a value must be in the given collection. */
|
||||
public CriteriaQueryBuilder<T> whereFieldIsIn(String fieldName, Collection<?> values) {
|
||||
return where(root.get(fieldName).in(values));
|
||||
}
|
||||
|
||||
/** Orders the result by the given operation applied to the given field. */
|
||||
public <U> CriteriaQueryBuilder<T> orderBy(OrderByClause<U> orderByClause, String fieldName) {
|
||||
Expression<U> expression = root.get(fieldName);
|
||||
return orderBy(orderByClause.order(expression));
|
||||
}
|
||||
|
||||
/** Builds and returns the query, applying all WHERE and ORDER BY clauses at once. */
|
||||
public CriteriaQuery<T> build() {
|
||||
Predicate[] predicateArray = predicates.build().toArray(new Predicate[0]);
|
||||
return query.where(predicateArray).orderBy(orders.build());
|
||||
}
|
||||
|
||||
private CriteriaQueryBuilder<T> where(Predicate predicate) {
|
||||
predicates.add(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
private CriteriaQueryBuilder<T> orderBy(Order order) {
|
||||
orders.add(order);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Creates a query builder that will SELECT from the given class. */
|
||||
public static <T> CriteriaQueryBuilder<T> create(Class<T> clazz) {
|
||||
CriteriaQuery<T> query = jpaTm().getEntityManager().getCriteriaBuilder().createQuery(clazz);
|
||||
Root<T> root = query.from(clazz);
|
||||
query = query.select(root);
|
||||
return new CriteriaQueryBuilder<>(query, root);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ package google.registry.rdap;
|
|||
import static com.google.common.base.Charsets.UTF_8;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.request.Actions.getPathForAction;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
|
@ -28,7 +29,10 @@ import com.google.common.net.MediaType;
|
|||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.DatabaseMigrationUtils;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.common.DatabaseTransitionSchedule.PrimaryDatabase;
|
||||
import google.registry.model.common.DatabaseTransitionSchedule.TransitionId;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapObjectClasses.ErrorResponse;
|
||||
|
@ -256,4 +260,11 @@ public abstract class RdapActionBase implements Runnable {
|
|||
DateTime getRequestTime() {
|
||||
return rdapJsonFormatter.getRequestTime();
|
||||
}
|
||||
|
||||
static boolean isDatastore() {
|
||||
return tm().transact(
|
||||
() ->
|
||||
DatabaseMigrationUtils.getPrimaryDatabase(TransitionId.REPLAYED_ENTITIES)
|
||||
.equals(PrimaryDatabase.DATASTORE));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package google.registry.rdap;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.rdap.RdapUtils.getRegistrarByIanaIdentifier;
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
|
@ -29,6 +31,9 @@ import com.google.common.primitives.Longs;
|
|||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.transaction.CriteriaQueryBuilder;
|
||||
import google.registry.rdap.RdapAuthorization.Role;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.SearchType;
|
||||
|
@ -112,7 +117,6 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
/** Parses the parameters and calls the appropriate search function. */
|
||||
@Override
|
||||
public EntitySearchResponse getSearchResponse(boolean isHeadRequest) {
|
||||
|
||||
// RDAP syntax example: /rdap/entities?fn=Bobby%20Joe*.
|
||||
if (Booleans.countTrue(fnParam.isPresent(), handleParam.isPresent()) != 1) {
|
||||
throw new BadRequestException("You must specify either fn=XXXX or handle=YYYY");
|
||||
|
@ -214,9 +218,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
// Don't allow wildcard suffixes when searching for entities.
|
||||
if (partialStringQuery.getHasWildcard() && (partialStringQuery.getSuffix() != null)) {
|
||||
throw new UnprocessableEntityException(
|
||||
partialStringQuery.getHasWildcard()
|
||||
? "Suffixes not allowed in wildcard entity name searches"
|
||||
: "Suffixes not allowed when searching for deleted entities");
|
||||
"Suffixes not allowed in wildcard entity name searches");
|
||||
}
|
||||
// For wildcards, make sure the initial string is long enough, except in the special case of
|
||||
// searching for all registrars, where we aren't worried about inefficient searches.
|
||||
|
@ -225,9 +227,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
&& (partialStringQuery.getInitialString().length()
|
||||
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH)) {
|
||||
throw new UnprocessableEntityException(
|
||||
partialStringQuery.getHasWildcard()
|
||||
? "Initial search string required in wildcard entity name searches"
|
||||
: "Initial search string required when searching for deleted entities");
|
||||
"Initial search string required in wildcard entity name searches");
|
||||
}
|
||||
// Get the registrar matches. If we have a registrar cursor, weed out registrars up to and
|
||||
// including the one we ended with last time. We can skip registrars if subtype is CONTACTS.
|
||||
|
@ -262,18 +262,39 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
|| (cursorType == CursorType.REGISTRAR)) {
|
||||
resultSet = RdapResultSet.create(ImmutableList.of());
|
||||
} else {
|
||||
Query<ContactResource> query =
|
||||
queryItems(
|
||||
ContactResource.class,
|
||||
"searchName",
|
||||
partialStringQuery,
|
||||
cursorQueryString, // if we get this far, and there's a cursor, it must be a contact
|
||||
DeletedItemHandling.EXCLUDE,
|
||||
rdapResultSetMaxSize + 1);
|
||||
if (rdapAuthorization.role() != RdapAuthorization.Role.ADMINISTRATOR) {
|
||||
query = query.filter("currentSponsorClientId in", rdapAuthorization.clientIds());
|
||||
if (isDatastore()) {
|
||||
Query<ContactResource> query =
|
||||
queryItems(
|
||||
ContactResource.class,
|
||||
"searchName",
|
||||
partialStringQuery,
|
||||
cursorQueryString, // if we get here and there's a cursor, it must be a contact
|
||||
DeletedItemHandling.EXCLUDE,
|
||||
rdapResultSetMaxSize + 1);
|
||||
if (!rdapAuthorization.role().equals(Role.ADMINISTRATOR)) {
|
||||
query = query.filter("currentSponsorClientId in", rdapAuthorization.clientIds());
|
||||
}
|
||||
resultSet = getMatchingResources(query, false, rdapResultSetMaxSize + 1);
|
||||
} else {
|
||||
resultSet =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
CriteriaQueryBuilder<ContactResource> builder =
|
||||
queryItemsSql(
|
||||
ContactResource.class,
|
||||
"searchName",
|
||||
partialStringQuery,
|
||||
cursorQueryString,
|
||||
DeletedItemHandling.EXCLUDE);
|
||||
if (!rdapAuthorization.role().equals(Role.ADMINISTRATOR)) {
|
||||
builder =
|
||||
builder.whereFieldIsIn(
|
||||
"currentSponsorClientId", rdapAuthorization.clientIds());
|
||||
}
|
||||
return getMatchingResourcesSql(builder, false, rdapResultSetMaxSize + 1);
|
||||
});
|
||||
}
|
||||
resultSet = getMatchingResources(query, false, rdapResultSetMaxSize + 1);
|
||||
}
|
||||
}
|
||||
return makeSearchResults(resultSet, registrars, QueryType.FULL_NAME);
|
||||
|
@ -303,15 +324,15 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
if (subtype == Subtype.REGISTRARS) {
|
||||
contactResourceList = ImmutableList.of();
|
||||
} else {
|
||||
ContactResource contactResource =
|
||||
ofy()
|
||||
.load()
|
||||
.type(ContactResource.class)
|
||||
.id(partialStringQuery.getInitialString())
|
||||
.now();
|
||||
Optional<ContactResource> contactResource =
|
||||
transactIfJpaTm(
|
||||
() ->
|
||||
tm().loadByKeyIfPresent(
|
||||
VKey.create(
|
||||
ContactResource.class, partialStringQuery.getInitialString())));
|
||||
contactResourceList =
|
||||
((contactResource != null) && shouldBeVisible(contactResource))
|
||||
? ImmutableList.of(contactResource)
|
||||
(contactResource.isPresent() && shouldBeVisible(contactResource.get()))
|
||||
? ImmutableList.of(contactResource.get())
|
||||
: ImmutableList.of();
|
||||
}
|
||||
ImmutableList<Registrar> registrarList;
|
||||
|
@ -365,16 +386,31 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
if (subtype == Subtype.REGISTRARS) {
|
||||
contactResultSet = RdapResultSet.create(ImmutableList.of());
|
||||
} else {
|
||||
contactResultSet =
|
||||
getMatchingResources(
|
||||
queryItemsByKey(
|
||||
ContactResource.class,
|
||||
partialStringQuery,
|
||||
cursorQueryString,
|
||||
getDeletedItemHandling(),
|
||||
querySizeLimit),
|
||||
shouldIncludeDeleted(),
|
||||
querySizeLimit);
|
||||
if (isDatastore()) {
|
||||
contactResultSet =
|
||||
getMatchingResources(
|
||||
queryItemsByKey(
|
||||
ContactResource.class,
|
||||
partialStringQuery,
|
||||
cursorQueryString,
|
||||
getDeletedItemHandling(),
|
||||
querySizeLimit),
|
||||
shouldIncludeDeleted(),
|
||||
querySizeLimit);
|
||||
} else {
|
||||
contactResultSet =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
getMatchingResourcesSql(
|
||||
queryItemsByKeySql(
|
||||
ContactResource.class,
|
||||
partialStringQuery,
|
||||
cursorQueryString,
|
||||
getDeletedItemHandling()),
|
||||
shouldIncludeDeleted(),
|
||||
querySizeLimit));
|
||||
}
|
||||
}
|
||||
return makeSearchResults(contactResultSet, registrars, QueryType.HANDLE);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package google.registry.rdap;
|
|||
|
||||
import static com.google.common.base.Charsets.UTF_8;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -24,6 +25,7 @@ import com.googlecode.objectify.Key;
|
|||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.persistence.transaction.CriteriaQueryBuilder;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.WildcardType;
|
||||
import google.registry.rdap.RdapSearchResults.BaseSearchResponse;
|
||||
|
@ -40,8 +42,10 @@ import java.util.ArrayList;
|
|||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
|
||||
/**
|
||||
* Base RDAP (new WHOIS) action for domain, nameserver and entity search requests.
|
||||
|
@ -161,14 +165,63 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
if (desiredRegistrar.isPresent()) {
|
||||
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||
}
|
||||
if (!checkForVisibility) {
|
||||
return RdapResultSet.create(query.list());
|
||||
List<T> queryResult = query.list();
|
||||
if (checkForVisibility) {
|
||||
return filterResourcesByVisibility(queryResult, querySizeLimit);
|
||||
} else {
|
||||
return RdapResultSet.create(queryResult);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In Cloud SQL, builds and runs the given query, and checks for permissioning if necessary.
|
||||
*
|
||||
* @param builder a query builder that represents the various SELECT FROM, WHERE, ORDER BY and
|
||||
* (etc) clauses that make up this SQL query
|
||||
* @param checkForVisibility true if the results should be checked to make sure they are visible;
|
||||
* normally this should be equal to the shouldIncludeDeleted setting, but in cases where the
|
||||
* query could not check deletion status (due to Datastore limitations such as the limit of
|
||||
* one field queried for inequality, for instance), it may need to be set to true even when
|
||||
* not including deleted records
|
||||
* @param querySizeLimit the maximum number of items the query is expected to return, usually
|
||||
* because the limit has been set
|
||||
* @return an {@link RdapResultSet} object containing the list of resources and an incompleteness
|
||||
* warning flag, which is set to MIGHT_BE_INCOMPLETE iff any resources were excluded due to
|
||||
* lack of visibility, and the resulting list of resources is less than the maximum allowable,
|
||||
* and the number of items returned by the query is greater than or equal to the maximum
|
||||
* number we might have expected
|
||||
*/
|
||||
<T extends EppResource> RdapResultSet<T> getMatchingResourcesSql(
|
||||
CriteriaQueryBuilder<T> builder, boolean checkForVisibility, int querySizeLimit) {
|
||||
jpaTm().assertInTransaction();
|
||||
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||
if (desiredRegistrar.isPresent()) {
|
||||
builder =
|
||||
builder.where(
|
||||
jpaTm().getEntityManager().getCriteriaBuilder()::equal,
|
||||
"currentSponsorClientId",
|
||||
desiredRegistrar.get());
|
||||
}
|
||||
List<T> queryResult =
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(builder.build())
|
||||
.setMaxResults(querySizeLimit)
|
||||
.getResultList();
|
||||
if (checkForVisibility) {
|
||||
return filterResourcesByVisibility(queryResult, querySizeLimit);
|
||||
} else {
|
||||
return RdapResultSet.create(queryResult);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends EppResource> RdapResultSet<T> filterResourcesByVisibility(
|
||||
List<T> queryResult, int querySizeLimit) {
|
||||
// If we are including deleted resources, we need to check that we're authorized for each one.
|
||||
List<T> resources = new ArrayList<>();
|
||||
int numResourcesQueried = 0;
|
||||
boolean someExcluded = false;
|
||||
for (T resource : query) {
|
||||
for (T resource : queryResult) {
|
||||
if (shouldBeVisible(resource)) {
|
||||
resources.add(resource);
|
||||
} else {
|
||||
|
@ -268,8 +321,8 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
// to be (more) sure we got everything.
|
||||
int getStandardQuerySizeLimit() {
|
||||
return shouldIncludeDeleted()
|
||||
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
||||
: (rdapResultSetMaxSize + 1);
|
||||
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
||||
: (rdapResultSetMaxSize + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -311,9 +364,10 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
query = query.filter(filterField, partialStringQuery.getInitialString());
|
||||
} else {
|
||||
// Ignore the suffix; the caller will need to filter on the suffix, if any.
|
||||
query = query
|
||||
.filter(filterField + " >=", partialStringQuery.getInitialString())
|
||||
.filter(filterField + " <", partialStringQuery.getNextInitialString());
|
||||
query =
|
||||
query
|
||||
.filter(filterField + " >=", partialStringQuery.getInitialString())
|
||||
.filter(filterField + " <", partialStringQuery.getNextInitialString());
|
||||
}
|
||||
if (cursorString.isPresent()) {
|
||||
query = query.filter(filterField + " >", cursorString.get());
|
||||
|
@ -321,6 +375,59 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
return setOtherQueryAttributes(query, deletedItemHandling, resultSetMaxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* In Cloud SQL, handles prefix searches in cases where, if we need to filter out deleted items,
|
||||
* there are no pending deletes.
|
||||
*
|
||||
* <p>In such cases, it is sufficient to check whether {@code deletionTime} is equal to {@code
|
||||
* END_OF_TIME}, because any other value means it has already been deleted. This allows us to use
|
||||
* an equality query for the deletion time.
|
||||
*
|
||||
* @param clazz the type of resource to be queried
|
||||
* @param filterField the database field of interest
|
||||
* @param partialStringQuery the details of the search string; if there is no wildcard, an
|
||||
* equality query is used; if there is a wildcard, a range query is used instead; the initial
|
||||
* string should not be empty, and any search suffix will be ignored, so the caller must
|
||||
* filter the results if a suffix is specified
|
||||
* @param cursorString if a cursor is present, this parameter should specify the cursor string, to
|
||||
* skip any results up to and including the string; empty() if there is no cursor
|
||||
* @param deletedItemHandling whether to include or exclude deleted items
|
||||
* @return a {@link CriteriaQueryBuilder} object representing the query so far
|
||||
*/
|
||||
static <T extends EppResource> CriteriaQueryBuilder<T> queryItemsSql(
|
||||
Class<T> clazz,
|
||||
String filterField,
|
||||
RdapSearchPattern partialStringQuery,
|
||||
Optional<String> cursorString,
|
||||
DeletedItemHandling deletedItemHandling) {
|
||||
jpaTm().assertInTransaction();
|
||||
if (partialStringQuery.getInitialString().length()
|
||||
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH) {
|
||||
throw new UnprocessableEntityException(
|
||||
String.format(
|
||||
"Initial search string must be at least %d characters",
|
||||
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||
}
|
||||
CriteriaBuilder criteriaBuilder = jpaTm().getEntityManager().getCriteriaBuilder();
|
||||
CriteriaQueryBuilder<T> builder = CriteriaQueryBuilder.create(clazz);
|
||||
if (partialStringQuery.getHasWildcard()) {
|
||||
builder =
|
||||
builder.where(
|
||||
criteriaBuilder::like,
|
||||
filterField,
|
||||
String.format("%s%%", partialStringQuery.getInitialString()));
|
||||
} else {
|
||||
// no wildcard means we use a standard equals query
|
||||
builder =
|
||||
builder.where(criteriaBuilder::equal, filterField, partialStringQuery.getInitialString());
|
||||
}
|
||||
if (cursorString.isPresent()) {
|
||||
builder = builder.where(criteriaBuilder::greaterThan, filterField, cursorString.get());
|
||||
}
|
||||
builder = builder.orderBy(criteriaBuilder::asc, filterField);
|
||||
return setDeletedItemHandlingSql(builder, deletedItemHandling);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles searches using a simple string rather than an {@link RdapSearchPattern}.
|
||||
*
|
||||
|
@ -331,9 +438,9 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
* @param filterField the database field of interest
|
||||
* @param queryString the search string
|
||||
* @param cursorField the field which should be compared to the cursor string, or empty() if the
|
||||
* key should be compared to a key created from the cursor string
|
||||
* key should be compared to a key created from the cursor string
|
||||
* @param cursorString if a cursor is present, this parameter should specify the cursor string, to
|
||||
* skip any results up to and including the string; empty() if there is no cursor
|
||||
* skip any results up to and including the string; empty() if there is no cursor
|
||||
* @param deletedItemHandling whether to include or exclude deleted items
|
||||
* @param resultSetMaxSize the maximum number of results to return
|
||||
* @return the query object
|
||||
|
@ -363,6 +470,50 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
return setOtherQueryAttributes(query, deletedItemHandling, resultSetMaxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* In Cloud SQL, handles searches using a simple string rather than an {@link RdapSearchPattern}.
|
||||
*
|
||||
* <p>Since the filter is not an inequality, we can support also checking a cursor string against
|
||||
* a different field (which involves an inequality on that field).
|
||||
*
|
||||
* @param clazz the type of resource to be queried
|
||||
* @param filterField the database field of interest
|
||||
* @param queryString the search string
|
||||
* @param cursorField the field which should be compared to the cursor string, or empty() if the
|
||||
* key should be compared to a key created from the cursor string
|
||||
* @param cursorString if a cursor is present, this parameter should specify the cursor string, to
|
||||
* skip any results up to and including the string; empty() if there is no cursor
|
||||
* @param deletedItemHandling whether to include or exclude deleted items
|
||||
* @return a {@link CriteriaQueryBuilder} object representing the query so far
|
||||
*/
|
||||
static <T extends EppResource> CriteriaQueryBuilder<T> queryItemsSql(
|
||||
Class<T> clazz,
|
||||
String filterField,
|
||||
String queryString,
|
||||
Optional<String> cursorField,
|
||||
Optional<String> cursorString,
|
||||
DeletedItemHandling deletedItemHandling) {
|
||||
if (queryString.length() < RdapSearchPattern.MIN_INITIAL_STRING_LENGTH) {
|
||||
throw new UnprocessableEntityException(
|
||||
String.format(
|
||||
"Initial search string must be at least %d characters",
|
||||
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||
}
|
||||
jpaTm().assertInTransaction();
|
||||
CriteriaQueryBuilder<T> builder = CriteriaQueryBuilder.create(clazz);
|
||||
CriteriaBuilder criteriaBuilder = jpaTm().getEntityManager().getCriteriaBuilder();
|
||||
builder = builder.where(criteriaBuilder::equal, filterField, queryString);
|
||||
if (cursorString.isPresent()) {
|
||||
if (cursorField.isPresent()) {
|
||||
builder =
|
||||
builder.where(criteriaBuilder::greaterThan, cursorField.get(), cursorString.get());
|
||||
} else {
|
||||
builder = builder.where(criteriaBuilder::greaterThan, "repoId", cursorString.get());
|
||||
}
|
||||
}
|
||||
return setDeletedItemHandlingSql(builder, deletedItemHandling);
|
||||
}
|
||||
|
||||
/** Handles searches where the field to be searched is the key. */
|
||||
static <T extends EppResource> Query<T> queryItemsByKey(
|
||||
Class<T> clazz,
|
||||
|
@ -382,9 +533,10 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
query = query.filterKey("=", Key.create(clazz, partialStringQuery.getInitialString()));
|
||||
} else {
|
||||
// Ignore the suffix; the caller will need to filter on the suffix, if any.
|
||||
query = query
|
||||
.filterKey(">=", Key.create(clazz, partialStringQuery.getInitialString()))
|
||||
.filterKey("<", Key.create(clazz, partialStringQuery.getNextInitialString()));
|
||||
query =
|
||||
query
|
||||
.filterKey(">=", Key.create(clazz, partialStringQuery.getInitialString()))
|
||||
.filterKey("<", Key.create(clazz, partialStringQuery.getNextInitialString()));
|
||||
}
|
||||
if (cursorString.isPresent()) {
|
||||
query = query.filterKey(">", Key.create(clazz, cursorString.get()));
|
||||
|
@ -392,6 +544,26 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
return setOtherQueryAttributes(query, deletedItemHandling, resultSetMaxSize);
|
||||
}
|
||||
|
||||
/** In Cloud SQL, handles searches where the field to be searched is the key. */
|
||||
static <T extends EppResource> CriteriaQueryBuilder<T> queryItemsByKeySql(
|
||||
Class<T> clazz,
|
||||
RdapSearchPattern partialStringQuery,
|
||||
Optional<String> cursorString,
|
||||
DeletedItemHandling deletedItemHandling) {
|
||||
jpaTm().assertInTransaction();
|
||||
return queryItemsSql(clazz, "repoId", partialStringQuery, cursorString, deletedItemHandling);
|
||||
}
|
||||
|
||||
static <T extends EppResource> CriteriaQueryBuilder<T> setDeletedItemHandlingSql(
|
||||
CriteriaQueryBuilder<T> builder, DeletedItemHandling deletedItemHandling) {
|
||||
if (!Objects.equals(deletedItemHandling, DeletedItemHandling.INCLUDE)) {
|
||||
builder =
|
||||
builder.where(
|
||||
jpaTm().getEntityManager().getCriteriaBuilder()::equal, "deletionTime", END_OF_TIME);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
static <T extends EppResource> Query<T> setOtherQueryAttributes(
|
||||
Query<T> query, DeletedItemHandling deletedItemHandling, int resultSetMaxSize) {
|
||||
if (deletedItemHandling != DeletedItemHandling.INCLUDE) {
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
// Copyright 2021 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.persistence.transaction;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.List;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Tests for {@link CriteriaQueryBuilder}. */
|
||||
class CriteriaQueryBuilderTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
private CriteriaQueryBuilderTestEntity entity1 =
|
||||
new CriteriaQueryBuilderTestEntity("name1", "data");
|
||||
private CriteriaQueryBuilderTestEntity entity2 =
|
||||
new CriteriaQueryBuilderTestEntity("name2", "zztz");
|
||||
private CriteriaQueryBuilderTestEntity entity3 = new CriteriaQueryBuilderTestEntity("zzz", "aaa");
|
||||
|
||||
@RegisterExtension
|
||||
final JpaUnitTestExtension jpaExtension =
|
||||
new JpaTestRules.Builder()
|
||||
.withClock(fakeClock)
|
||||
.withEntityClass(CriteriaQueryBuilderTestEntity.class)
|
||||
.buildUnitTestRule();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
jpaTm().transact(() -> jpaTm().putAll(ImmutableList.of(entity1, entity2, entity3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noWhereClause() {
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
|
||||
.build())
|
||||
.getResultList()))
|
||||
.containsExactly(entity1, entity2, entity3)
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_where_exactlyOne() {
|
||||
List<CriteriaQueryBuilderTestEntity> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
CriteriaQuery<CriteriaQueryBuilderTestEntity> query =
|
||||
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
|
||||
.where(
|
||||
jpaTm().getEntityManager().getCriteriaBuilder()::equal,
|
||||
"data",
|
||||
"zztz")
|
||||
.build();
|
||||
return jpaTm().getEntityManager().createQuery(query).getResultList();
|
||||
});
|
||||
assertThat(result).containsExactly(entity2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_where_like_oneResult() {
|
||||
List<CriteriaQueryBuilderTestEntity> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
CriteriaQuery<CriteriaQueryBuilderTestEntity> query =
|
||||
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
|
||||
.where(
|
||||
jpaTm().getEntityManager().getCriteriaBuilder()::like, "data", "a%")
|
||||
.build();
|
||||
return jpaTm().getEntityManager().createQuery(query).getResultList();
|
||||
});
|
||||
assertThat(result).containsExactly(entity3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_where_like_twoResults() {
|
||||
List<CriteriaQueryBuilderTestEntity> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
CriteriaQuery<CriteriaQueryBuilderTestEntity> query =
|
||||
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
|
||||
.where(
|
||||
jpaTm().getEntityManager().getCriteriaBuilder()::like, "data", "%a%")
|
||||
.build();
|
||||
return jpaTm().getEntityManager().createQuery(query).getResultList();
|
||||
});
|
||||
assertThat(result).containsExactly(entity1, entity3).inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_multipleWheres() {
|
||||
List<CriteriaQueryBuilderTestEntity> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
CriteriaQuery<CriteriaQueryBuilderTestEntity> query =
|
||||
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
|
||||
// first "where" matches 1 and 3
|
||||
.where(
|
||||
jpaTm().getEntityManager().getCriteriaBuilder()::like, "data", "%a%")
|
||||
// second "where" matches 1 and 2
|
||||
.where(
|
||||
jpaTm().getEntityManager().getCriteriaBuilder()::like, "data", "%t%")
|
||||
.build();
|
||||
return jpaTm().getEntityManager().createQuery(query).getResultList();
|
||||
});
|
||||
assertThat(result).containsExactly(entity1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_where_in_oneResult() {
|
||||
List<CriteriaQueryBuilderTestEntity> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
CriteriaQuery<CriteriaQueryBuilderTestEntity> query =
|
||||
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
|
||||
.whereFieldIsIn("data", ImmutableList.of("aaa", "bbb"))
|
||||
.build();
|
||||
return jpaTm().getEntityManager().createQuery(query).getResultList();
|
||||
});
|
||||
assertThat(result).containsExactly(entity3).inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_where_in_twoResults() {
|
||||
List<CriteriaQueryBuilderTestEntity> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
CriteriaQuery<CriteriaQueryBuilderTestEntity> query =
|
||||
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
|
||||
.whereFieldIsIn("data", ImmutableList.of("aaa", "bbb", "data"))
|
||||
.build();
|
||||
return jpaTm().getEntityManager().createQuery(query).getResultList();
|
||||
});
|
||||
assertThat(result).containsExactly(entity1, entity3).inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_orderBy() {
|
||||
List<CriteriaQueryBuilderTestEntity> result =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
CriteriaQuery<CriteriaQueryBuilderTestEntity> query =
|
||||
CriteriaQueryBuilder.create(CriteriaQueryBuilderTestEntity.class)
|
||||
.orderBy(jpaTm().getEntityManager().getCriteriaBuilder()::asc, "data")
|
||||
.where(
|
||||
jpaTm().getEntityManager().getCriteriaBuilder()::like, "data", "%a%")
|
||||
.build();
|
||||
return jpaTm().getEntityManager().createQuery(query).getResultList();
|
||||
});
|
||||
assertThat(result).containsExactly(entity3, entity1).inOrder();
|
||||
}
|
||||
|
||||
@Entity(name = "CriteriaQueryBuilderTestEntity")
|
||||
private static class CriteriaQueryBuilderTestEntity extends ImmutableObject {
|
||||
@Id private String name;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String data;
|
||||
|
||||
private CriteriaQueryBuilderTestEntity() {}
|
||||
|
||||
private CriteriaQueryBuilderTestEntity(String name, String data) {
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,14 +43,16 @@ import google.registry.model.reporting.HistoryEntry;
|
|||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.SearchType;
|
||||
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link RdapEntitySearchAction}. */
|
||||
@DualDatabaseTest
|
||||
class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySearchAction> {
|
||||
|
||||
RdapEntitySearchActionTest() {
|
||||
|
@ -209,9 +211,9 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
.asBuilder()
|
||||
.setRepoId(String.format("%04d-ROID", i))
|
||||
.build();
|
||||
resourcesBuilder.add(contact);
|
||||
resourcesBuilder.add(makeHistoryEntry(
|
||||
contact, HistoryEntry.Type.CONTACT_CREATE, null, "created", clock.nowUtc()));
|
||||
resourcesBuilder.add(contact);
|
||||
}
|
||||
persistResources(resourcesBuilder.build());
|
||||
for (int i = 1; i <= numRegistrars; i++) {
|
||||
|
@ -386,7 +388,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testInvalidPath_rejected() {
|
||||
action.requestPath = actionPath + "/path";
|
||||
action.run();
|
||||
|
@ -394,7 +396,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(Optional.empty(), 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testInvalidRequest_rejected() {
|
||||
action.run();
|
||||
assertThat(parseJsonObject(response.getPayload()))
|
||||
|
@ -405,7 +407,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(Optional.empty(), 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatch_suffixRejected() {
|
||||
assertThat(generateActualJsonWithFullName("exam*ple"))
|
||||
.isEqualTo(
|
||||
|
@ -417,7 +419,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatch_suffixRejected() {
|
||||
assertThat(generateActualJsonWithHandle("exam*ple"))
|
||||
.isEqualTo(
|
||||
|
@ -429,7 +431,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testMultipleWildcards_rejected() {
|
||||
assertThat(generateActualJsonWithHandle("*.*"))
|
||||
.isEqualTo(
|
||||
|
@ -441,7 +443,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNoCharactersToMatch_rejected() {
|
||||
rememberWildcardType("*");
|
||||
assertThat(generateActualJsonWithHandle("*"))
|
||||
|
@ -453,7 +455,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFewerThanTwoCharactersToMatch_rejected() {
|
||||
rememberWildcardType("a*");
|
||||
assertThat(generateActualJsonWithHandle("a*"))
|
||||
|
@ -465,7 +467,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testInvalidSubtype_rejected() {
|
||||
action.subtypeParam = Optional.of("Space Aliens");
|
||||
assertThat(generateActualJsonWithFullName("Blinky (赤ベイ)"))
|
||||
|
@ -478,14 +480,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(Optional.empty(), 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_found() {
|
||||
login("2-RegistrarTest");
|
||||
runSuccessfulNameTestWithBlinky("Blinky (赤ベイ)", "rdap_contact.json");
|
||||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_found_subtypeAll() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("aLl");
|
||||
|
@ -493,7 +495,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_found_subtypeContacts() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("cONTACTS");
|
||||
|
@ -501,7 +503,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_subtypeRegistrars() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("Registrars");
|
||||
|
@ -509,7 +511,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_found_specifyingSameRegistrar() {
|
||||
login("2-RegistrarTest");
|
||||
action.registrarParam = Optional.of("2-RegistrarTest");
|
||||
|
@ -517,7 +519,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_specifyingOtherRegistrar() {
|
||||
login("2-RegistrarTest");
|
||||
action.registrarParam = Optional.of("2-RegistrarInact");
|
||||
|
@ -525,7 +527,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_found_asAdministrator() {
|
||||
loginAsAdmin();
|
||||
rememberWildcardType("Blinky (赤ベイ)");
|
||||
|
@ -533,27 +535,27 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_notLoggedIn() {
|
||||
runNotFoundNameTest("Blinky (赤ベイ)");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_loggedInAsOtherRegistrar() {
|
||||
login("2-Registrar");
|
||||
runNotFoundNameTest("Blinky (赤ベイ)");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_found_wildcard() {
|
||||
login("2-RegistrarTest");
|
||||
runSuccessfulNameTestWithBlinky("Blinky*", "rdap_contact.json");
|
||||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_found_wildcardSpecifyingSameRegistrar() {
|
||||
login("2-RegistrarTest");
|
||||
action.registrarParam = Optional.of("2-RegistrarTest");
|
||||
|
@ -561,7 +563,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_wildcardSpecifyingOtherRegistrar() {
|
||||
login("2-RegistrarTest");
|
||||
action.registrarParam = Optional.of("2-RegistrarInact");
|
||||
|
@ -569,7 +571,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_found_wildcardBoth() {
|
||||
login("2-RegistrarTest");
|
||||
rememberWildcardType("Blin*");
|
||||
|
@ -579,14 +581,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_deleted() {
|
||||
login("2-RegistrarTest");
|
||||
runNotFoundNameTest("Cl*");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_deletedWhenLoggedInAsOtherRegistrar() {
|
||||
login("2-RegistrarTest");
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -594,7 +596,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_deletedWhenLoggedInAsSameRegistrar() {
|
||||
login("2-Registrar");
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -602,7 +604,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContact_notFound_deletedWhenLoggedInAsAdmin() {
|
||||
loginAsAdmin();
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -610,7 +612,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_found() {
|
||||
login("2-RegistrarTest");
|
||||
runSuccessfulNameTest(
|
||||
|
@ -618,7 +620,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_found_subtypeAll() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("all");
|
||||
|
@ -627,7 +629,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_found_subtypeRegistrars() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("REGISTRARS");
|
||||
|
@ -636,7 +638,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_notFound_subtypeContacts() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("contacts");
|
||||
|
@ -644,7 +646,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_found_specifyingSameRegistrar() {
|
||||
action.registrarParam = Optional.of("2-Registrar");
|
||||
runSuccessfulNameTest(
|
||||
|
@ -652,25 +654,26 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_notFound_specifyingDifferentRegistrar() {
|
||||
action.registrarParam = Optional.of("2-RegistrarTest");
|
||||
runNotFoundNameTest("Yes Virginia <script>");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContacts_nonTruncated() {
|
||||
login("2-RegistrarTest");
|
||||
createManyContactsAndRegistrars(4, 0, registrarTest);
|
||||
rememberWildcardType("Entity *");
|
||||
// JsonObject foo = generateActualJsonWithFullName("Entity *");
|
||||
assertThat(generateActualJsonWithFullName("Entity *"))
|
||||
.isEqualTo(generateExpectedJson("rdap_nontruncated_contacts.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContacts_truncated() {
|
||||
login("2-RegistrarTest");
|
||||
createManyContactsAndRegistrars(5, 0, registrarTest);
|
||||
|
@ -683,7 +686,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContacts_reallyTruncated() {
|
||||
login("2-RegistrarTest");
|
||||
createManyContactsAndRegistrars(9, 0, registrarTest);
|
||||
|
@ -697,7 +700,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchContacts_cursorNavigation() throws Exception {
|
||||
login("2-RegistrarTest");
|
||||
createManyContactsAndRegistrars(9, 0, registrarTest);
|
||||
|
@ -716,7 +719,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
"Entity 9"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrars_nonTruncated() {
|
||||
createManyContactsAndRegistrars(0, 4, registrarTest);
|
||||
rememberWildcardType("Entity *");
|
||||
|
@ -726,7 +729,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrars_truncated() {
|
||||
createManyContactsAndRegistrars(0, 5, registrarTest);
|
||||
rememberWildcardType("Entity *");
|
||||
|
@ -738,7 +741,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrars_reallyTruncated() {
|
||||
createManyContactsAndRegistrars(0, 9, registrarTest);
|
||||
rememberWildcardType("Entity *");
|
||||
|
@ -750,7 +753,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrars_cursorNavigation() throws Exception {
|
||||
createManyContactsAndRegistrars(0, 13, registrarTest);
|
||||
checkCursorNavigation(
|
||||
|
@ -772,7 +775,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
"Entity 9"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrars_cursorNavigationThroughAll() throws Exception {
|
||||
createManyContactsAndRegistrars(0, 13, registrarTest);
|
||||
action.subtypeParam = Optional.of("registrars");
|
||||
|
@ -798,7 +801,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
"Yes Virginia <script>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchMix_truncated() {
|
||||
login("2-RegistrarTest");
|
||||
createManyContactsAndRegistrars(3, 3, registrarTest);
|
||||
|
@ -811,7 +814,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(3, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchMix_cursorNavigation() throws Exception {
|
||||
login("2-RegistrarTest");
|
||||
createManyContactsAndRegistrars(3, 3, registrarTest);
|
||||
|
@ -827,7 +830,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
"Entity 6"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchMix_subtypeContacts() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("contacts");
|
||||
|
@ -839,7 +842,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchMix_subtypeRegistrars() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("registrars");
|
||||
|
@ -849,13 +852,13 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_notFound_inactive() {
|
||||
runNotFoundNameTest("No Way");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_notFound_inactiveAsDifferentRegistrar() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
login("2-Registrar");
|
||||
|
@ -863,7 +866,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_found_inactiveAsSameRegistrar() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
login("2-RegistrarInact");
|
||||
|
@ -871,7 +874,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_found_inactiveAsAdmin() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
loginAsAdmin();
|
||||
|
@ -879,13 +882,13 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_notFound_test() {
|
||||
runNotFoundNameTest("Da Test Registrar");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_notFound_testAsDifferentRegistrar() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
login("2-Registrar");
|
||||
|
@ -893,7 +896,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_found_testAsSameRegistrar() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
login("2-RegistrarTest");
|
||||
|
@ -902,7 +905,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testNameMatchRegistrar_found_testAsAdmin() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
loginAsAdmin();
|
||||
|
@ -911,14 +914,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found() {
|
||||
login("2-RegistrarTest");
|
||||
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact.json");
|
||||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_subtypeAll() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("all");
|
||||
|
@ -926,7 +929,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_subtypeContacts() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("contacts");
|
||||
|
@ -934,7 +937,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_notFound_subtypeRegistrars() {
|
||||
login("2-RegistrarTest");
|
||||
action.subtypeParam = Optional.of("reGistrars");
|
||||
|
@ -942,28 +945,28 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_specifyingSameRegistrar() {
|
||||
action.registrarParam = Optional.of("2-RegistrarTest");
|
||||
runSuccessfulHandleTestWithBlinky("2-ROID", "rdap_contact_no_personal_data_with_remark.json");
|
||||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_notFound_specifyingDifferentRegistrar() {
|
||||
action.registrarParam = Optional.of("2-Registrar");
|
||||
runNotFoundHandleTest("2-ROID");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_notFound_deleted() {
|
||||
login("2-RegistrarTest");
|
||||
runNotFoundHandleTest("6-ROID");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_notFound_deletedWhenLoggedInAsOtherRegistrar() {
|
||||
login("2-RegistrarTest");
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -971,7 +974,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_deletedWhenLoggedInAsSameRegistrar() {
|
||||
login("2-Registrar");
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -985,7 +988,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_deletedWhenLoggedInAsAdmin() {
|
||||
loginAsAdmin();
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -999,14 +1002,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_notFound_deletedWildcard() {
|
||||
login("2-RegistrarTest");
|
||||
runNotFoundHandleTest("6-ROI*");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_notFound_deletedWildcardWhenLoggedInAsOtherRegistrar() {
|
||||
login("2-RegistrarTest");
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -1014,7 +1017,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_deletedWildcardWhenLoggedInAsSameRegistrar() {
|
||||
login("2-Registrar");
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -1028,7 +1031,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_deletedWildcardWhenLoggedInAsAdmin() {
|
||||
loginAsAdmin();
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
|
@ -1042,48 +1045,48 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_found() {
|
||||
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
|
||||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_found_subtypeAll() {
|
||||
action.subtypeParam = Optional.of("all");
|
||||
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
|
||||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_found_subtypeRegistrars() {
|
||||
action.subtypeParam = Optional.of("registrars");
|
||||
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
|
||||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_notFound_subtypeContacts() {
|
||||
action.subtypeParam = Optional.of("contacts");
|
||||
runNotFoundHandleTest("20");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_found_specifyingSameRegistrar() {
|
||||
action.registrarParam = Optional.of("2-Registrar");
|
||||
runSuccessfulHandleTest("20", "20", "Yes Virginia <script>", "rdap_registrar.json");
|
||||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_notFound_specifyingDifferentRegistrar() {
|
||||
action.registrarParam = Optional.of("2-RegistrarTest");
|
||||
runNotFoundHandleTest("20");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_wildcardWithResultSetSizeOne() {
|
||||
login("2-RegistrarTest");
|
||||
action.rdapResultSetMaxSize = 1;
|
||||
|
@ -1091,14 +1094,14 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_wildcard() {
|
||||
login("2-RegistrarTest");
|
||||
runSuccessfulHandleTestWithBlinky("2-RO*", "rdap_contact.json");
|
||||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_wildcardSpecifyingSameRegistrar() {
|
||||
action.registrarParam = Optional.of("2-RegistrarTest");
|
||||
login("2-RegistrarTest");
|
||||
|
@ -1106,7 +1109,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_notFound_wildcardSpecifyingDifferentRegistrar() {
|
||||
action.registrarParam = Optional.of("2-Registrar");
|
||||
login("2-RegistrarTest");
|
||||
|
@ -1114,20 +1117,20 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_found_deleted() {
|
||||
login("2-RegistrarTest");
|
||||
runSuccessfulHandleTestWithBlinky("2-RO*", "rdap_contact.json");
|
||||
verifyMetrics(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_notFound_wildcard() {
|
||||
runNotFoundHandleTest("20*");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_cursorNavigationWithFullLastPage() throws Exception {
|
||||
login("2-RegistrarTest");
|
||||
createManyContactsAndRegistrars(12, 0, registrarTest);
|
||||
|
@ -1150,7 +1153,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
"Entity 12"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchContact_cursorNavigationWithPartialLastPage() throws Exception {
|
||||
login("2-RegistrarTest");
|
||||
createManyContactsAndRegistrars(13, 0, registrarTest);
|
||||
|
@ -1174,13 +1177,13 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
"Entity 13"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_notFound_wildcard() {
|
||||
runNotFoundHandleTest("3test*");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrars_cursorNavigationThroughAll() throws Exception {
|
||||
createManyContactsAndRegistrars(0, 13, registrarTest);
|
||||
action.subtypeParam = Optional.of("registrars");
|
||||
|
@ -1206,7 +1209,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
"Yes Virginia <script>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchMix_found_truncated() {
|
||||
createManyContactsAndRegistrars(30, 0, registrarTest);
|
||||
rememberWildcardType("00*");
|
||||
|
@ -1216,13 +1219,13 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_notFound_inactive() {
|
||||
runNotFoundHandleTest("21");
|
||||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_notFound_inactiveAsDifferentRegistrar() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
login("2-Registrar");
|
||||
|
@ -1230,7 +1233,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyErrorMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_found_inactiveAsSameRegistrar() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
login("2-RegistrarInact");
|
||||
|
@ -1238,7 +1241,7 @@ class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEntitySear
|
|||
verifyMetrics(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testHandleMatchRegistrar_found_inactiveAsAdmin() {
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
loginAsAdmin();
|
||||
|
|
|
@ -17,10 +17,12 @@ package google.registry.testing;
|
|||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.io.Files.asCharSink;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.persistSimpleResources;
|
||||
import static google.registry.testing.DualDatabaseTestInvocationContextProvider.injectTmForDualDatabaseTest;
|
||||
import static google.registry.testing.DualDatabaseTestInvocationContextProvider.restoreTmAfterDualDatabaseTest;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
@ -40,10 +42,16 @@ import com.google.common.base.Joiner;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.io.Files;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.ObjectifyFilter;
|
||||
import google.registry.model.common.DatabaseTransitionSchedule;
|
||||
import google.registry.model.common.DatabaseTransitionSchedule.PrimaryDatabase;
|
||||
import google.registry.model.common.DatabaseTransitionSchedule.PrimaryDatabaseTransition;
|
||||
import google.registry.model.common.DatabaseTransitionSchedule.TransitionId;
|
||||
import google.registry.model.common.TimedTransitionProperty;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.Registrar.State;
|
||||
|
@ -390,6 +398,14 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa
|
|||
loadInitialData();
|
||||
}
|
||||
} else {
|
||||
// If we're using SQL, set replayed entities to use SQL
|
||||
DatabaseTransitionSchedule schedule =
|
||||
DatabaseTransitionSchedule.create(
|
||||
TransitionId.REPLAYED_ENTITIES,
|
||||
TimedTransitionProperty.fromValueMap(
|
||||
ImmutableSortedMap.of(START_OF_TIME, PrimaryDatabase.CLOUD_SQL),
|
||||
PrimaryDatabaseTransition.class));
|
||||
tm().transactNew(() -> ofy().saveWithoutBackup().entity(schedule).now());
|
||||
if (withCloudSql && !withJpaUnitTest && !withoutCannedData) {
|
||||
loadInitialData();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue