mirror of
https://github.com/google/nomulus.git
synced 2025-05-28 11:10:57 +02:00
RDAP: Implement entity name search
Adds the ability to search for entities (contacts and registrars) by name. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=130305930
This commit is contained in:
parent
64abebec82
commit
160266f37a
8 changed files with 368 additions and 66 deletions
|
@ -80,4 +80,8 @@
|
||||||
<property name="deletionTime" direction="asc"/>
|
<property name="deletionTime" direction="asc"/>
|
||||||
<property name="fullyQualifiedHostName" direction="asc"/>
|
<property name="fullyQualifiedHostName" direction="asc"/>
|
||||||
</datastore-index>
|
</datastore-index>
|
||||||
|
<datastore-index kind="ContactResource" ancestor="false" source="manual">
|
||||||
|
<property name="deletionTime" direction="asc"/>
|
||||||
|
<property name="searchName" direction="asc"/>
|
||||||
|
</datastore-index>
|
||||||
</datastore-indexes>
|
</datastore-indexes>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import com.google.common.collect.Lists;
|
||||||
import com.googlecode.objectify.annotation.Cache;
|
import com.googlecode.objectify.annotation.Cache;
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
import com.googlecode.objectify.annotation.Entity;
|
||||||
import com.googlecode.objectify.annotation.IgnoreSave;
|
import com.googlecode.objectify.annotation.IgnoreSave;
|
||||||
|
import com.googlecode.objectify.annotation.Index;
|
||||||
import com.googlecode.objectify.condition.IfNull;
|
import com.googlecode.objectify.condition.IfNull;
|
||||||
import google.registry.model.EppResource;
|
import google.registry.model.EppResource;
|
||||||
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
||||||
|
@ -85,6 +86,15 @@ public class ContactResource extends EppResource implements ForeignKeyedEppResou
|
||||||
@XmlTransient
|
@XmlTransient
|
||||||
PostalInfo internationalizedPostalInfo;
|
PostalInfo internationalizedPostalInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contact name used for name searches. This is set automatically to be the internationalized
|
||||||
|
* postal name, or if null, the localized postal name, or if that is null as well, null. Personal
|
||||||
|
* info; cleared by wipeOut().
|
||||||
|
*/
|
||||||
|
@Index
|
||||||
|
@XmlTransient
|
||||||
|
String searchName;
|
||||||
|
|
||||||
/** Contact’s voice number. Personal info; cleared by wipeOut(). */
|
/** Contact’s voice number. Personal info; cleared by wipeOut(). */
|
||||||
@IgnoreSave(IfNull.class)
|
@IgnoreSave(IfNull.class)
|
||||||
ContactPhoneNumber voice;
|
ContactPhoneNumber voice;
|
||||||
|
@ -250,6 +260,16 @@ public class ContactResource extends EppResource implements ForeignKeyedEppResou
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContactResource build() {
|
public ContactResource build() {
|
||||||
|
// Set the searchName using the internationalized and localized postal info names.
|
||||||
|
if ((getInstance().internationalizedPostalInfo != null)
|
||||||
|
&& (getInstance().internationalizedPostalInfo.getName() != null)) {
|
||||||
|
getInstance().searchName = getInstance().internationalizedPostalInfo.getName();
|
||||||
|
} else if ((getInstance().localizedPostalInfo != null)
|
||||||
|
&& (getInstance().localizedPostalInfo.getName() != null)) {
|
||||||
|
getInstance().searchName = getInstance().localizedPostalInfo.getName();
|
||||||
|
} else {
|
||||||
|
getInstance().searchName = null;
|
||||||
|
}
|
||||||
return super.build();
|
return super.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -786,7 +786,7 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Load a registrar entity by its client id. */
|
/** Load a registrar entity by its client id outside of a transaction. */
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Registrar loadByClientId(final String clientId) {
|
public static Registrar loadByClientId(final String clientId) {
|
||||||
return ofy().doTransactionless(new Work<Registrar>() {
|
return ofy().doTransactionless(new Work<Registrar>() {
|
||||||
|
@ -801,7 +801,7 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load registrar entities by client id range.
|
* Load registrar entities by client id range outside of a transaction.
|
||||||
*
|
*
|
||||||
* @param clientIdStart returned registrars will have a client id greater than or equal to this
|
* @param clientIdStart returned registrars will have a client id greater than or equal to this
|
||||||
* @param clientIdAfterEnd returned registrars will have a client id less than this
|
* @param clientIdAfterEnd returned registrars will have a client id less than this
|
||||||
|
@ -820,6 +820,41 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Load a registrar entity by its name outside of a transaction. */
|
||||||
|
@Nullable
|
||||||
|
public static Registrar loadByName(final String name) {
|
||||||
|
return ofy().doTransactionless(new Work<Registrar>() {
|
||||||
|
@Override
|
||||||
|
public Registrar run() {
|
||||||
|
return ofy().load()
|
||||||
|
.type(Registrar.class)
|
||||||
|
.filter("registrarName", name)
|
||||||
|
.first()
|
||||||
|
.now();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load registrar entities by registrar name range, inclusive of the start but not the end,
|
||||||
|
* outside of a transaction.
|
||||||
|
*
|
||||||
|
* @param nameStart returned registrars will have a name greater than or equal to this
|
||||||
|
* @param nameAfterEnd returned registrars will have a name less than this
|
||||||
|
* @param resultSetMaxSize the maximum number of registrar entities to be returned
|
||||||
|
*/
|
||||||
|
public static Iterable<Registrar> loadByNameRange(
|
||||||
|
final String nameStart, final String nameAfterEnd, final int resultSetMaxSize) {
|
||||||
|
return ofy().doTransactionless(new Work<Iterable<Registrar>>() {
|
||||||
|
@Override
|
||||||
|
public Iterable<Registrar> run() {
|
||||||
|
return ofy().load()
|
||||||
|
.type(Registrar.class)
|
||||||
|
.filter("registrarName >=", nameStart)
|
||||||
|
.filter("registrarName <", nameAfterEnd)
|
||||||
|
.limit(resultSetMaxSize);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
/** Loads all registrar entities. */
|
/** Loads all registrar entities. */
|
||||||
public static Iterable<Registrar> loadAll() {
|
public static Iterable<Registrar> loadAll() {
|
||||||
return ofy().load().type(Registrar.class).ancestor(getCrossTldKey());
|
return ofy().load().type(Registrar.class).ancestor(getCrossTldKey());
|
||||||
|
|
|
@ -24,7 +24,6 @@ import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.primitives.Booleans;
|
import com.google.common.primitives.Booleans;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.cmd.Query;
|
|
||||||
import google.registry.config.ConfigModule.Config;
|
import google.registry.config.ConfigModule.Config;
|
||||||
import google.registry.model.contact.ContactResource;
|
import google.registry.model.contact.ContactResource;
|
||||||
import google.registry.model.domain.DesignatedContact;
|
import google.registry.model.domain.DesignatedContact;
|
||||||
|
@ -34,7 +33,6 @@ import google.registry.request.Action;
|
||||||
import google.registry.request.HttpException;
|
import google.registry.request.HttpException;
|
||||||
import google.registry.request.HttpException.BadRequestException;
|
import google.registry.request.HttpException.BadRequestException;
|
||||||
import google.registry.request.HttpException.NotFoundException;
|
import google.registry.request.HttpException.NotFoundException;
|
||||||
import google.registry.request.HttpException.NotImplementedException;
|
|
||||||
import google.registry.request.HttpException.UnprocessableEntityException;
|
import google.registry.request.HttpException.UnprocessableEntityException;
|
||||||
import google.registry.request.Parameter;
|
import google.registry.request.Parameter;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
|
@ -88,15 +86,8 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
||||||
ImmutableList<ImmutableMap<String, Object>> results;
|
ImmutableList<ImmutableMap<String, Object>> results;
|
||||||
if (fnParam.isPresent()) {
|
if (fnParam.isPresent()) {
|
||||||
// syntax: /rdap/entities?fn=Bobby%20Joe*
|
// syntax: /rdap/entities?fn=Bobby%20Joe*
|
||||||
// TODO(b/25973399): implement entity name search, and move the comment below to that routine
|
// The name is the contact name or registrar name (not registrar contact name).
|
||||||
// As per Gustavo Lozano of ICANN, registrar name search should be by registrar name only, not
|
results = searchByName(RdapSearchPattern.create(fnParam.get(), false), now);
|
||||||
// by registrar contact name:
|
|
||||||
//
|
|
||||||
// The search is by registrar name only. The profile is supporting the functionality defined
|
|
||||||
// in the Base Registry Agreement (see 1.6 of Section 4 of the Base Registry Agreement,
|
|
||||||
// https://newgtlds.icann.org/sites/default/files/agreements/
|
|
||||||
// agreement-approved-09jan14-en.htm).
|
|
||||||
throw new NotImplementedException("Entity name search not implemented");
|
|
||||||
} else {
|
} else {
|
||||||
// syntax: /rdap/entities?handle=12345-*
|
// syntax: /rdap/entities?handle=12345-*
|
||||||
// The handle is either the contact roid or the registrar clientId.
|
// The handle is either the contact roid or the registrar clientId.
|
||||||
|
@ -111,6 +102,57 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for entities by name, returning a JSON array of entity info maps.
|
||||||
|
*
|
||||||
|
* <p>As per Gustavo Lozano of ICANN, registrar name search should be by registrar name only, not
|
||||||
|
* by registrar contact name:
|
||||||
|
*
|
||||||
|
* <p>The search is by registrar name only. The profile is supporting the functionality defined
|
||||||
|
* in the Base Registry Agreement (see 1.6 of Section 4 of the Base Registry Agreement,
|
||||||
|
* https://newgtlds.icann.org/sites/default/files/agreements/
|
||||||
|
* agreement-approved-09jan14-en.htm).
|
||||||
|
*
|
||||||
|
* <p>According to RFC 7482 section 6.1, punycode is only used for domain name labels, so we can
|
||||||
|
* assume that entity names are regular unicode.
|
||||||
|
*/
|
||||||
|
private ImmutableList<ImmutableMap<String, Object>>
|
||||||
|
searchByName(final RdapSearchPattern partialStringQuery, DateTime now) throws HttpException {
|
||||||
|
// Handle queries without a wildcard -- load by name, which may not be unique.
|
||||||
|
if (!partialStringQuery.getHasWildcard()) {
|
||||||
|
Registrar registrar = Registrar.loadByName(partialStringQuery.getInitialString());
|
||||||
|
return makeSearchResults(
|
||||||
|
ofy().load()
|
||||||
|
.type(ContactResource.class)
|
||||||
|
.filter("searchName", partialStringQuery.getInitialString())
|
||||||
|
.filter("deletionTime", END_OF_TIME)
|
||||||
|
.limit(rdapResultSetMaxSize),
|
||||||
|
(registrar == null)
|
||||||
|
? ImmutableList.<Registrar>of() : ImmutableList.of(registrar),
|
||||||
|
now);
|
||||||
|
// Handle queries with a wildcard, but no suffix. For contact resources, the deletion time will
|
||||||
|
// always be END_OF_TIME for non-deleted records; unlike domain resources, we don't need to
|
||||||
|
// worry about deletion times in the future. That allows us to use an equality query for the
|
||||||
|
// deletion time.
|
||||||
|
} else if (partialStringQuery.getSuffix() == null) {
|
||||||
|
return makeSearchResults(
|
||||||
|
ofy().load()
|
||||||
|
.type(ContactResource.class)
|
||||||
|
.filter("searchName >=", partialStringQuery.getInitialString())
|
||||||
|
.filter("searchName <", partialStringQuery.getNextInitialString())
|
||||||
|
.filter("deletionTime", END_OF_TIME)
|
||||||
|
.limit(rdapResultSetMaxSize),
|
||||||
|
Registrar.loadByNameRange(
|
||||||
|
partialStringQuery.getInitialString(),
|
||||||
|
partialStringQuery.getNextInitialString(),
|
||||||
|
rdapResultSetMaxSize),
|
||||||
|
now);
|
||||||
|
// Don't allow suffixes in entity name search queries.
|
||||||
|
} else {
|
||||||
|
throw new UnprocessableEntityException("Suffixes not allowed in entity name searches");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Searches for entities by handle, returning a JSON array of entity info maps. */
|
/** Searches for entities by handle, returning a JSON array of entity info maps. */
|
||||||
private ImmutableList<ImmutableMap<String, Object>> searchByHandle(
|
private ImmutableList<ImmutableMap<String, Object>> searchByHandle(
|
||||||
final RdapSearchPattern partialStringQuery, DateTime now) throws HttpException {
|
final RdapSearchPattern partialStringQuery, DateTime now) throws HttpException {
|
||||||
|
@ -121,63 +163,62 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
||||||
.id(partialStringQuery.getInitialString())
|
.id(partialStringQuery.getInitialString())
|
||||||
.now();
|
.now();
|
||||||
Registrar registrar = Registrar.loadByClientId(partialStringQuery.getInitialString());
|
Registrar registrar = Registrar.loadByClientId(partialStringQuery.getInitialString());
|
||||||
ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>();
|
return makeSearchResults(
|
||||||
if ((contactResource != null) && contactResource.getDeletionTime().isEqual(END_OF_TIME)) {
|
((contactResource == null) || !contactResource.getDeletionTime().isEqual(END_OF_TIME))
|
||||||
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
|
? ImmutableList.<ContactResource>of() : ImmutableList.of(contactResource),
|
||||||
// they are global, and might have different roles for different domains.
|
(registrar == null)
|
||||||
builder.add(RdapJsonFormatter.makeRdapJsonForContact(
|
? ImmutableList.<Registrar>of() : ImmutableList.of(registrar),
|
||||||
contactResource,
|
now);
|
||||||
false,
|
|
||||||
Optional.<DesignatedContact.Type>absent(),
|
|
||||||
rdapLinkBase,
|
|
||||||
rdapWhoisServer,
|
|
||||||
now));
|
|
||||||
}
|
|
||||||
if ((registrar != null) && registrar.isActiveAndPubliclyVisible()) {
|
|
||||||
builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar(
|
|
||||||
registrar, false, rdapLinkBase, rdapWhoisServer, now));
|
|
||||||
}
|
|
||||||
return builder.build();
|
|
||||||
// Handle queries with a wildcard, but no suffix. For contact resources, the deletion time will
|
// Handle queries with a wildcard, but no suffix. For contact resources, the deletion time will
|
||||||
// always be END_OF_TIME for non-deleted records; unlike domain resources, we don't need to
|
// always be END_OF_TIME for non-deleted records; unlike domain resources, we don't need to
|
||||||
// worry about deletion times in the future. That allows us to use an equality query for the
|
// worry about deletion times in the future. That allows us to use an equality query for the
|
||||||
// deletion time.
|
// deletion time.
|
||||||
} else if (partialStringQuery.getSuffix() == null) {
|
} else if (partialStringQuery.getSuffix() == null) {
|
||||||
ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>();
|
return makeSearchResults(
|
||||||
Query<ContactResource> query = ofy().load()
|
ofy().load()
|
||||||
.type(ContactResource.class)
|
.type(ContactResource.class)
|
||||||
.filterKey(">=", Key.create(ContactResource.class, partialStringQuery.getInitialString()))
|
.filterKey(
|
||||||
.filterKey(
|
">=", Key.create(ContactResource.class, partialStringQuery.getInitialString()))
|
||||||
"<", Key.create(ContactResource.class, partialStringQuery.getNextInitialString()))
|
.filterKey(
|
||||||
.filter("deletionTime", END_OF_TIME)
|
"<", Key.create(ContactResource.class, partialStringQuery.getNextInitialString()))
|
||||||
.limit(rdapResultSetMaxSize);
|
.filter("deletionTime", END_OF_TIME)
|
||||||
for (ContactResource contactResource : query) {
|
.limit(rdapResultSetMaxSize),
|
||||||
builder.add(RdapJsonFormatter.makeRdapJsonForContact(
|
Registrar.loadByClientIdRange(
|
||||||
contactResource,
|
|
||||||
false,
|
|
||||||
Optional.<DesignatedContact.Type>absent(),
|
|
||||||
rdapLinkBase,
|
|
||||||
rdapWhoisServer,
|
|
||||||
now));
|
|
||||||
}
|
|
||||||
for (Registrar registrar
|
|
||||||
: Registrar.loadByClientIdRange(
|
|
||||||
partialStringQuery.getInitialString(),
|
partialStringQuery.getInitialString(),
|
||||||
partialStringQuery.getNextInitialString(),
|
partialStringQuery.getNextInitialString(),
|
||||||
rdapResultSetMaxSize)) {
|
rdapResultSetMaxSize),
|
||||||
if (registrar.isActiveAndPubliclyVisible()) {
|
now);
|
||||||
builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar(
|
|
||||||
registrar, false, rdapLinkBase, rdapWhoisServer, now));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// In theory, there could be more results than our max size, so limit the size.
|
|
||||||
ImmutableList<ImmutableMap<String, Object>> resultSet = builder.build();
|
|
||||||
return (resultSet.size() <= rdapResultSetMaxSize)
|
|
||||||
? resultSet
|
|
||||||
: resultSet.subList(0, rdapResultSetMaxSize);
|
|
||||||
// Don't allow suffixes in entity handle search queries.
|
// Don't allow suffixes in entity handle search queries.
|
||||||
} else {
|
} else {
|
||||||
throw new UnprocessableEntityException("Suffixes not allowed in entity handle searches");
|
throw new UnprocessableEntityException("Suffixes not allowed in entity handle searches");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Builds a JSON array of entity info maps based on the specified contacts and registrars. */
|
||||||
|
private ImmutableList<ImmutableMap<String, Object>> makeSearchResults(
|
||||||
|
Iterable<ContactResource> contactResources, Iterable<Registrar> registrars, DateTime now)
|
||||||
|
throws HttpException {
|
||||||
|
ImmutableList.Builder<ImmutableMap<String, Object>> builder = new ImmutableList.Builder<>();
|
||||||
|
for (ContactResource contact : contactResources) {
|
||||||
|
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
|
||||||
|
// they are global, and might have different roles for different domains.
|
||||||
|
builder.add(RdapJsonFormatter.makeRdapJsonForContact(
|
||||||
|
contact,
|
||||||
|
false,
|
||||||
|
Optional.<DesignatedContact.Type>absent(),
|
||||||
|
rdapLinkBase,
|
||||||
|
rdapWhoisServer, now));
|
||||||
|
}
|
||||||
|
for (Registrar registrar : registrars) {
|
||||||
|
if (registrar.isActiveAndPubliclyVisible()) {
|
||||||
|
builder.add(RdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||||
|
registrar, false, rdapLinkBase, rdapWhoisServer, now));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// In theory, there could be more results than our max size, so limit the size.
|
||||||
|
ImmutableList<ImmutableMap<String, Object>> resultSet = builder.build();
|
||||||
|
return (resultSet.size() <= rdapResultSetMaxSize)
|
||||||
|
? resultSet
|
||||||
|
: resultSet.subList(0, rdapResultSetMaxSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,8 @@ public class ContactResourceTest extends EntityTestCase {
|
||||||
verifyIndexing(
|
verifyIndexing(
|
||||||
contactResource,
|
contactResource,
|
||||||
"deletionTime",
|
"deletionTime",
|
||||||
"currentSponsorClientId");
|
"currentSponsorClientId",
|
||||||
|
"searchName");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -157,6 +157,7 @@ class google.registry.model.contact.ContactResource {
|
||||||
java.lang.String currentSponsorClientId;
|
java.lang.String currentSponsorClientId;
|
||||||
java.lang.String email;
|
java.lang.String email;
|
||||||
java.lang.String lastEppUpdateClientId;
|
java.lang.String lastEppUpdateClientId;
|
||||||
|
java.lang.String searchName;
|
||||||
java.util.Set<google.registry.model.eppcommon.StatusValue> status;
|
java.util.Set<google.registry.model.eppcommon.StatusValue> status;
|
||||||
org.joda.time.DateTime deletionTime;
|
org.joda.time.DateTime deletionTime;
|
||||||
org.joda.time.DateTime lastEppUpdateTime;
|
org.joda.time.DateTime lastEppUpdateTime;
|
||||||
|
|
|
@ -85,6 +85,13 @@ public class RdapEntitySearchActionTest {
|
||||||
ImmutableList.of("123 Blinky St", "Blinkyland"),
|
ImmutableList.of("123 Blinky St", "Blinkyland"),
|
||||||
clock.nowUtc());
|
clock.nowUtc());
|
||||||
|
|
||||||
|
makeAndPersistContactResource(
|
||||||
|
"blindly",
|
||||||
|
"Blindly",
|
||||||
|
"blindly@b.tld",
|
||||||
|
ImmutableList.of("123 Blindly St", "Blindlyland"),
|
||||||
|
clock.nowUtc());
|
||||||
|
|
||||||
// deleted
|
// deleted
|
||||||
persistResource(
|
persistResource(
|
||||||
makeContactResource("clyde", "Clyde (愚図た)", "clyde@c.tld")
|
makeContactResource("clyde", "Clyde (愚図た)", "clyde@c.tld")
|
||||||
|
@ -188,7 +195,15 @@ public class RdapEntitySearchActionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuffix_rejected() throws Exception {
|
public void testNameMatch_suffixRejected() throws Exception {
|
||||||
|
assertThat(generateActualJsonWithFullName("exam*ple"))
|
||||||
|
.isEqualTo(
|
||||||
|
generateExpectedJson("Suffix not allowed after wildcard", "rdap_error_422.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(422);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandleMatch_suffixRejected() throws Exception {
|
||||||
assertThat(generateActualJsonWithHandle("exam*ple"))
|
assertThat(generateActualJsonWithHandle("exam*ple"))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
generateExpectedJson("Suffix not allowed after wildcard", "rdap_error_422.json"));
|
generateExpectedJson("Suffix not allowed after wildcard", "rdap_error_422.json"));
|
||||||
|
@ -212,11 +227,51 @@ public class RdapEntitySearchActionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameMatch_notImplemented() throws Exception {
|
public void testNameMatch_contactFound() throws Exception {
|
||||||
assertThat(generateActualJsonWithFullName("hello"))
|
assertThat(generateActualJsonWithFullName("Blinky (赤ベイ)"))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
generateExpectedJson("Entity name search not implemented", "rdap_error_501.json"));
|
generateExpectedJsonForEntity(
|
||||||
assertThat(response.getStatus()).isEqualTo(501);
|
"2-ROID",
|
||||||
|
"Blinky (赤ベイ)",
|
||||||
|
"blinky@b.tld",
|
||||||
|
"\"123 Blinky St\", \"Blinkyland\"",
|
||||||
|
"rdap_contact.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_contactWildcardFound() throws Exception {
|
||||||
|
assertThat(generateActualJsonWithFullName("Blinky*"))
|
||||||
|
.isEqualTo(
|
||||||
|
generateExpectedJsonForEntity(
|
||||||
|
"2-ROID",
|
||||||
|
"Blinky (赤ベイ)",
|
||||||
|
"blinky@b.tld",
|
||||||
|
"\"123 Blinky St\", \"Blinkyland\"",
|
||||||
|
"rdap_contact.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_contactWildcardFoundBoth() throws Exception {
|
||||||
|
assertThat(generateActualJsonWithFullName("Blin*"))
|
||||||
|
.isEqualTo(generateExpectedJson("rdap_multiple_contacts2.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_deletedContactNotFound() throws Exception {
|
||||||
|
generateActualJsonWithFullName("Cl*");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_registrarFound() throws Exception {
|
||||||
|
assertThat(generateActualJsonWithFullName("Yes Virginia <script>"))
|
||||||
|
.isEqualTo(
|
||||||
|
generateExpectedJsonForEntity(
|
||||||
|
"2-Registrar", "Yes Virginia <script>", null, null, "rdap_registrar.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -253,6 +308,12 @@ public class RdapEntitySearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_testAndInactiveRegistrars_notFound() throws Exception {
|
||||||
|
generateActualJsonWithHandle("No Way");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHandleMatch_2rstar_found() throws Exception {
|
public void testHandleMatch_2rstar_found() throws Exception {
|
||||||
assertThat(generateActualJsonWithHandle("2-R*"))
|
assertThat(generateActualJsonWithHandle("2-R*"))
|
||||||
|
|
139
javatests/google/registry/rdap/testdata/rdap_multiple_contacts2.json
vendored
Normal file
139
javatests/google/registry/rdap/testdata/rdap_multiple_contacts2.json
vendored
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
{
|
||||||
|
"entitySearchResults":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"objectClassName" : "entity",
|
||||||
|
"handle" : "4-ROID",
|
||||||
|
"status" : ["active"],
|
||||||
|
"links" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"value" : "https://example.com/rdap/entity/4-ROID",
|
||||||
|
"rel" : "self",
|
||||||
|
"href": "https://example.com/rdap/entity/4-ROID",
|
||||||
|
"type" : "application/rdap+json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"eventAction": "registration",
|
||||||
|
"eventActor": "foo",
|
||||||
|
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"eventAction": "last update of RDAP database",
|
||||||
|
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vcardArray" :
|
||||||
|
[
|
||||||
|
"vcard",
|
||||||
|
[
|
||||||
|
["version", {}, "text", "4.0"],
|
||||||
|
["fn", {}, "text", "Blindly"],
|
||||||
|
["org", {}, "text", "GOOGLE INCORPORATED <script>"],
|
||||||
|
["adr", {}, "text",
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
["123 Blindly St", "Blindlyland"],
|
||||||
|
"KOKOMO",
|
||||||
|
"BM",
|
||||||
|
"31337",
|
||||||
|
"United States"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
["tel", {"type" : ["voice"]}, "uri", "tel:+1.2126660420"],
|
||||||
|
["tel", {"type" : ["fax"]}, "uri", "tel:+1.2126660420"],
|
||||||
|
["email", {}, "text", "blindly@b.tld"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"objectClassName" : "entity",
|
||||||
|
"handle" : "2-ROID",
|
||||||
|
"status" : ["active"],
|
||||||
|
"links" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"value" : "https://example.com/rdap/entity/2-ROID",
|
||||||
|
"rel" : "self",
|
||||||
|
"href": "https://example.com/rdap/entity/2-ROID",
|
||||||
|
"type" : "application/rdap+json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"eventAction": "registration",
|
||||||
|
"eventActor": "foo",
|
||||||
|
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"eventAction": "last update of RDAP database",
|
||||||
|
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vcardArray" :
|
||||||
|
[
|
||||||
|
"vcard",
|
||||||
|
[
|
||||||
|
["version", {}, "text", "4.0"],
|
||||||
|
["fn", {}, "text", "Blinky (赤ベイ)"],
|
||||||
|
["org", {}, "text", "GOOGLE INCORPORATED <script>"],
|
||||||
|
["adr", {}, "text",
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
["123 Blinky St", "Blinkyland"],
|
||||||
|
"KOKOMO",
|
||||||
|
"BM",
|
||||||
|
"31337",
|
||||||
|
"United States"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
["tel", {"type" : ["voice"]}, "uri", "tel:+1.2126660420"],
|
||||||
|
["tel", {"type" : ["fax"]}, "uri", "tel:+1.2126660420"],
|
||||||
|
["email", {}, "text", "blinky@b.tld"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rdapConformance": [ "rdap_level_0" ],
|
||||||
|
"notices" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"title" : "RDAP Terms of Service",
|
||||||
|
"description" :
|
||||||
|
[
|
||||||
|
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
|
||||||
|
"Any information provided is 'as is' without any guarantee of accuracy.",
|
||||||
|
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
|
||||||
|
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
|
||||||
|
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of Charleston Road Registry or any ICANN-accredited registrar.",
|
||||||
|
"You may only use the information contained in the Domain Database for lawful purposes.",
|
||||||
|
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
|
||||||
|
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
|
||||||
|
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
|
||||||
|
"We reserve the right to modify this agreement at any time."
|
||||||
|
],
|
||||||
|
"links" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"value" : "https://example.com/rdap/help/tos",
|
||||||
|
"rel" : "alternate",
|
||||||
|
"href" : "https://www.registry.google/about/rdap/tos.html",
|
||||||
|
"type" : "text/html"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"remarks" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"description" :
|
||||||
|
[
|
||||||
|
"This response conforms to the RDAP Operational Profile for gTLD Registries and Registrars version 1.0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue