mirror of
https://github.com/google/nomulus.git
synced 2025-07-23 03:06:01 +02:00
Add golden files for request component routing maps
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157026188
This commit is contained in:
parent
bb67841884
commit
ddb0f5692e
23 changed files with 514 additions and 39 deletions
|
@ -38,7 +38,7 @@ import javax.inject.Inject;
|
|||
)
|
||||
public class RdapAutnumAction extends RdapActionBase {
|
||||
|
||||
public static final String PATH = "/rdap/autnum";
|
||||
public static final String PATH = "/rdap/autnum/";
|
||||
|
||||
@Inject RdapAutnumAction() {}
|
||||
|
||||
|
|
|
@ -64,7 +64,6 @@ import org.joda.time.DateTime;
|
|||
@Action(
|
||||
path = RdapDomainSearchAction.PATH,
|
||||
method = {GET, HEAD},
|
||||
isPrefix = true,
|
||||
auth = @Auth(minimumLevel = AuthLevel.NONE, userPolicy = Auth.UserPolicy.PUBLIC)
|
||||
)
|
||||
public class RdapDomainSearchAction extends RdapActionBase {
|
||||
|
|
|
@ -61,7 +61,6 @@ import org.joda.time.DateTime;
|
|||
@Action(
|
||||
path = RdapEntitySearchAction.PATH,
|
||||
method = {GET, HEAD},
|
||||
isPrefix = true,
|
||||
auth = @Auth(minimumLevel = AuthLevel.NONE, userPolicy = Auth.UserPolicy.PUBLIC)
|
||||
)
|
||||
public class RdapEntitySearchAction extends RdapActionBase {
|
||||
|
@ -144,7 +143,7 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
|||
// Get the registrar matches, depending on whether there's a wildcard.
|
||||
ImmutableList<Registrar> registrarMatches =
|
||||
FluentIterable.from(Registrar.loadAllCached())
|
||||
.filter(
|
||||
.filter(
|
||||
new Predicate<Registrar>() {
|
||||
@Override
|
||||
public boolean apply(Registrar registrar) {
|
||||
|
@ -170,7 +169,7 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
|||
.type(ContactResource.class)
|
||||
.id(partialStringQuery.getInitialString())
|
||||
.now();
|
||||
ImmutableList<Registrar> registrars =
|
||||
ImmutableList<Registrar> registrars =
|
||||
getMatchingRegistrars(partialStringQuery.getInitialString());
|
||||
return makeSearchResults(
|
||||
((contactResource == null) || !contactResource.getDeletionTime().isEqual(END_OF_TIME))
|
||||
|
|
|
@ -38,7 +38,7 @@ import javax.inject.Inject;
|
|||
)
|
||||
public class RdapIpAction extends RdapActionBase {
|
||||
|
||||
public static final String PATH = "/rdap/ip";
|
||||
public static final String PATH = "/rdap/ip/";
|
||||
|
||||
@Inject RdapIpAction() {}
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ import org.joda.time.DateTime;
|
|||
@Action(
|
||||
path = RdapNameserverSearchAction.PATH,
|
||||
method = {GET, HEAD},
|
||||
isPrefix = true,
|
||||
auth = @Auth(minimumLevel = AuthLevel.NONE, userPolicy = Auth.UserPolicy.PUBLIC)
|
||||
)
|
||||
public class RdapNameserverSearchAction extends RdapActionBase {
|
||||
|
|
|
@ -25,12 +25,14 @@ import com.google.common.base.Function;
|
|||
@AutoValue
|
||||
abstract class Route {
|
||||
|
||||
static Route create(Action action, Function<Object, Runnable> instantiator) {
|
||||
return new AutoValue_Route(action, instantiator);
|
||||
static Route create(
|
||||
Action action, Function<Object, Runnable> instantiator, Class<?> actionClass) {
|
||||
return new AutoValue_Route(action, instantiator, actionClass);
|
||||
}
|
||||
|
||||
abstract Action action();
|
||||
abstract Function<Object, Runnable> instantiator();
|
||||
abstract Class<?> actionClass();
|
||||
|
||||
boolean isMethodAllowed(Action.Method requestMethod) {
|
||||
for (Action.Method method : action().method()) {
|
||||
|
|
|
@ -65,8 +65,7 @@ final class Router {
|
|||
return Optional.absent();
|
||||
}
|
||||
|
||||
private static
|
||||
ImmutableSortedMap<String, Route> extractRoutesFromComponent(Class<?> componentClass) {
|
||||
static ImmutableSortedMap<String, Route> extractRoutesFromComponent(Class<?> componentClass) {
|
||||
ImmutableSortedMap.Builder<String, Route> routes =
|
||||
new ImmutableSortedMap.Builder<>(Ordering.natural());
|
||||
for (Method method : componentClass.getMethods()) {
|
||||
|
@ -79,9 +78,12 @@ final class Router {
|
|||
if (action == null) {
|
||||
continue;
|
||||
}
|
||||
@SuppressWarnings("unchecked") // Safe due to previous checks.
|
||||
@SuppressWarnings("unchecked") // Safe due to previous checks.
|
||||
Route route =
|
||||
Route.create(action, (Function<Object, Runnable>) newInstantiator(method));
|
||||
Route.create(
|
||||
action,
|
||||
(Function<Object, Runnable>) newInstantiator(method),
|
||||
method.getReturnType());
|
||||
routes.put(action.path(), route);
|
||||
}
|
||||
return routes.build();
|
||||
|
|
169
java/google/registry/request/RouterDisplayHelper.java
Normal file
169
java/google/registry/request/RouterDisplayHelper.java
Normal file
|
@ -0,0 +1,169 @@
|
|||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.request;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility class to help in dumping routing maps.
|
||||
*
|
||||
* <p>Each of the App Engine services (frontend, backend, and tools) has a Dagger component used for
|
||||
* routing requests (e.g. FrontendRequestComponent). This class produces a text file representation
|
||||
* of the routing configuration, showing what paths map to what action classes, as well as the
|
||||
* properties of the action classes' annotations (which cover things like allowable HTTP methods,
|
||||
* authentication settings, etc.). The text file can be useful for documentation, and is also used
|
||||
* in unit tests to check against golden routing maps to find possibly unexpected changes.
|
||||
*
|
||||
* <p>The file has fixed-width columns with a header row. The width of the columns is determined by
|
||||
* the content to be displayed. The columns are:
|
||||
*
|
||||
* <ol>
|
||||
* <li>the URL path which maps to this action (with a "(*)" after it if the prefix flag is set)
|
||||
* <li>the simple name of the action class
|
||||
* <li>the allowable HTTP methods
|
||||
* <li>whether to automatically print "ok" in the response
|
||||
* <li>whether XSRF protection is enabled
|
||||
* <li>the XSRF scope
|
||||
* <li>whether login is required
|
||||
* <li>the allowable authentication methods
|
||||
* <li>the minimum authentication level
|
||||
* <li>the user policy
|
||||
* </ol>
|
||||
*
|
||||
* <p>See the Auth class for more information about authentication settings.
|
||||
*/
|
||||
public class RouterDisplayHelper {
|
||||
|
||||
private static final String PATH = "path";
|
||||
private static final String CLASS = "class";
|
||||
private static final String METHODS = "methods";
|
||||
private static final String XSRF_SCOPE = "xsrfScope";
|
||||
private static final String AUTH_METHODS = "authMethods";
|
||||
private static final String MINIMUM_LEVEL = "minLevel";
|
||||
|
||||
private static final String FORMAT =
|
||||
"%%-%ds %%-%ds %%-%ds %%-2s %%-4s %%-%ds %%-5s %%-%ds %%-%ds %%s";
|
||||
|
||||
/** Returns a string representation of the routing map in the specified component. */
|
||||
public static String extractHumanReadableRoutesFromComponent(Class<?> componentClass) {
|
||||
return formatRoutes(Router.extractRoutesFromComponent(componentClass).values());
|
||||
}
|
||||
|
||||
private static String getFormatString(Map<String, Integer> columnWidths) {
|
||||
return String.format(
|
||||
FORMAT,
|
||||
columnWidths.get(PATH),
|
||||
columnWidths.get(CLASS),
|
||||
columnWidths.get(METHODS),
|
||||
columnWidths.get(XSRF_SCOPE),
|
||||
columnWidths.get(AUTH_METHODS),
|
||||
columnWidths.get(MINIMUM_LEVEL));
|
||||
}
|
||||
|
||||
private static String headerToString(String formatString) {
|
||||
return String.format(
|
||||
formatString,
|
||||
"PATH",
|
||||
"CLASS",
|
||||
"METHODS",
|
||||
"OK",
|
||||
"XSRF",
|
||||
"SCOPE",
|
||||
"LOGIN",
|
||||
"AUTH_METHODS",
|
||||
"MIN",
|
||||
"USER_POLICY");
|
||||
}
|
||||
|
||||
private static String routeToString(Route route, String formatString) {
|
||||
return String.format(
|
||||
formatString,
|
||||
route.action().isPrefix() ? (route.action().path() + "(*)") : route.action().path(),
|
||||
route.actionClass().getSimpleName(),
|
||||
Joiner.on(",").join(route.action().method()),
|
||||
route.action().automaticallyPrintOk() ? "y" : "n",
|
||||
route.action().xsrfProtection() ? "y" : "n",
|
||||
route.action().xsrfScope(),
|
||||
route.action().requireLogin() ? "y" : "n",
|
||||
Joiner.on(",").join(route.action().auth().methods()),
|
||||
route.action().auth().minimumLevel(),
|
||||
route.action().auth().userPolicy());
|
||||
}
|
||||
|
||||
private static String formatRoutes(Iterable<Route> routes) {
|
||||
|
||||
// Use the column header length as a minimum.
|
||||
int pathWidth = 4;
|
||||
int classWidth = 5;
|
||||
int methodsWidth = 7;
|
||||
int xsrfScopeWidth = 5;
|
||||
int authMethodsWidth = 12;
|
||||
int minLevelWidth = 3;
|
||||
for (Route route : routes) {
|
||||
int len =
|
||||
route.action().isPrefix()
|
||||
? (route.action().path().length() + 3)
|
||||
: route.action().path().length();
|
||||
if (len > pathWidth) {
|
||||
pathWidth = len;
|
||||
}
|
||||
len = route.actionClass().getSimpleName().length();
|
||||
if (len > classWidth) {
|
||||
classWidth = len;
|
||||
}
|
||||
len = Joiner.on(",").join(route.action().method()).length();
|
||||
if (len > methodsWidth) {
|
||||
methodsWidth = len;
|
||||
}
|
||||
len = route.action().xsrfScope().length();
|
||||
if (len > xsrfScopeWidth) {
|
||||
xsrfScopeWidth = len;
|
||||
}
|
||||
len = Joiner.on(",").join(route.action().auth().methods()).length();
|
||||
if (len > authMethodsWidth) {
|
||||
authMethodsWidth = len;
|
||||
}
|
||||
len = route.action().auth().minimumLevel().toString().length();
|
||||
if (len > minLevelWidth) {
|
||||
minLevelWidth = len;
|
||||
}
|
||||
}
|
||||
final String formatString =
|
||||
getFormatString(
|
||||
new ImmutableMap.Builder<String, Integer>()
|
||||
.put(PATH, pathWidth)
|
||||
.put(CLASS, classWidth)
|
||||
.put(METHODS, methodsWidth)
|
||||
.put(XSRF_SCOPE, xsrfScopeWidth)
|
||||
.put(AUTH_METHODS, authMethodsWidth)
|
||||
.put(MINIMUM_LEVEL, minLevelWidth)
|
||||
.build());
|
||||
return headerToString(formatString)
|
||||
+ String.format("%n")
|
||||
+ FluentIterable.from(routes)
|
||||
.transform(
|
||||
new Function<Route, String>() {
|
||||
@Override
|
||||
public String apply(Route route) {
|
||||
return routeToString(route, formatString);
|
||||
}
|
||||
})
|
||||
.join(Joiner.on(String.format("%n")));
|
||||
}
|
||||
}
|
|
@ -47,6 +47,9 @@ java_library(
|
|||
"//java/google/registry/keyring/kms",
|
||||
"//java/google/registry/loadtest",
|
||||
"//java/google/registry/model",
|
||||
"//java/google/registry/module/backend",
|
||||
"//java/google/registry/module/frontend",
|
||||
"//java/google/registry/module/tools",
|
||||
"//java/google/registry/pricing",
|
||||
"//java/google/registry/rde",
|
||||
"//java/google/registry/request",
|
||||
|
|
40
java/google/registry/tools/GetRoutingMapCommand.java
Normal file
40
java/google/registry/tools/GetRoutingMapCommand.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.request.RouterDisplayHelper;
|
||||
|
||||
/** Generates the routing map file used for unit testing. */
|
||||
@Parameters(commandDescription = "Generate a routing map file")
|
||||
final class GetRoutingMapCommand implements Command {
|
||||
|
||||
@Parameter(
|
||||
names = {"-c", "--class"},
|
||||
description =
|
||||
"Request component class (e.g. google.registry.module.backend.BackendRequestComponent)"
|
||||
+ " for which routing map should be generated",
|
||||
required = true
|
||||
)
|
||||
private String serviceClassName;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
System.out.println(
|
||||
RouterDisplayHelper.extractHumanReadableRoutesFromComponent(
|
||||
Class.forName(serviceClassName)));
|
||||
}
|
||||
}
|
|
@ -79,6 +79,7 @@ public final class RegistryTool {
|
|||
.put("get_lrp_token", GetLrpTokenCommand.class)
|
||||
.put("get_registrar", GetRegistrarCommand.class)
|
||||
.put("get_resource_by_key", GetResourceByKeyCommand.class)
|
||||
.put("get_routing_map", GetRoutingMapCommand.class)
|
||||
.put("get_schema", GetSchemaCommand.class)
|
||||
.put("get_schema_tree", GetSchemaTreeCommand.class)
|
||||
.put("get_tld", GetTldCommand.class)
|
||||
|
|
|
@ -26,17 +26,21 @@ import java.net.URL;
|
|||
/** Utility methods related to reading java resources. */
|
||||
public final class ResourceUtils {
|
||||
|
||||
/** Loads a file as a string, assuming UTF-8 encoding. */
|
||||
/** Loads a resource from a file as a string, assuming UTF-8 encoding. */
|
||||
public static String readResourceUtf8(String filename) {
|
||||
return resourceToString(getResource(filename));
|
||||
return readResourceUtf8(getResource(filename));
|
||||
}
|
||||
|
||||
/** Loads a file (specified relative to the contextClass) as a string, assuming UTF-8 encoding. */
|
||||
/**
|
||||
* Loads a resource from a file (specified relative to the contextClass) as a string, assuming
|
||||
* UTF-8 encoding.
|
||||
*/
|
||||
public static String readResourceUtf8(Class<?> contextClass, String filename) {
|
||||
return resourceToString(getResource(contextClass, filename));
|
||||
return readResourceUtf8(getResource(contextClass, filename));
|
||||
}
|
||||
|
||||
private static String resourceToString(URL url) {
|
||||
/** Loads a resource from a URL as a string, assuming UTF-8 encoding. */
|
||||
public static String readResourceUtf8(URL url) {
|
||||
try {
|
||||
return Resources.toString(url, UTF_8);
|
||||
} catch (IOException e) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue