diff --git a/java/google/registry/rdap/RdapAutnumAction.java b/java/google/registry/rdap/RdapAutnumAction.java index f89709105..50ee6e4f7 100644 --- a/java/google/registry/rdap/RdapAutnumAction.java +++ b/java/google/registry/rdap/RdapAutnumAction.java @@ -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() {} diff --git a/java/google/registry/rdap/RdapDomainSearchAction.java b/java/google/registry/rdap/RdapDomainSearchAction.java index 28224e6cb..9ac3ed2a6 100644 --- a/java/google/registry/rdap/RdapDomainSearchAction.java +++ b/java/google/registry/rdap/RdapDomainSearchAction.java @@ -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 { diff --git a/java/google/registry/rdap/RdapEntitySearchAction.java b/java/google/registry/rdap/RdapEntitySearchAction.java index 4c4d07936..483eb7dcf 100644 --- a/java/google/registry/rdap/RdapEntitySearchAction.java +++ b/java/google/registry/rdap/RdapEntitySearchAction.java @@ -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 registrarMatches = FluentIterable.from(Registrar.loadAllCached()) - .filter( + .filter( new Predicate() { @Override public boolean apply(Registrar registrar) { @@ -170,7 +169,7 @@ public class RdapEntitySearchAction extends RdapActionBase { .type(ContactResource.class) .id(partialStringQuery.getInitialString()) .now(); - ImmutableList registrars = + ImmutableList registrars = getMatchingRegistrars(partialStringQuery.getInitialString()); return makeSearchResults( ((contactResource == null) || !contactResource.getDeletionTime().isEqual(END_OF_TIME)) diff --git a/java/google/registry/rdap/RdapIpAction.java b/java/google/registry/rdap/RdapIpAction.java index 1bcc4a1a9..08624d64f 100644 --- a/java/google/registry/rdap/RdapIpAction.java +++ b/java/google/registry/rdap/RdapIpAction.java @@ -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() {} diff --git a/java/google/registry/rdap/RdapNameserverSearchAction.java b/java/google/registry/rdap/RdapNameserverSearchAction.java index d10582208..c8689732a 100644 --- a/java/google/registry/rdap/RdapNameserverSearchAction.java +++ b/java/google/registry/rdap/RdapNameserverSearchAction.java @@ -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 { diff --git a/java/google/registry/request/Route.java b/java/google/registry/request/Route.java index 8741a2c32..763eb0a3b 100644 --- a/java/google/registry/request/Route.java +++ b/java/google/registry/request/Route.java @@ -25,12 +25,14 @@ import com.google.common.base.Function; @AutoValue abstract class Route { - static Route create(Action action, Function instantiator) { - return new AutoValue_Route(action, instantiator); + static Route create( + Action action, Function instantiator, Class actionClass) { + return new AutoValue_Route(action, instantiator, actionClass); } abstract Action action(); abstract Function instantiator(); + abstract Class actionClass(); boolean isMethodAllowed(Action.Method requestMethod) { for (Action.Method method : action().method()) { diff --git a/java/google/registry/request/Router.java b/java/google/registry/request/Router.java index dcb54bf6f..910d6a66e 100644 --- a/java/google/registry/request/Router.java +++ b/java/google/registry/request/Router.java @@ -65,8 +65,7 @@ final class Router { return Optional.absent(); } - private static - ImmutableSortedMap extractRoutesFromComponent(Class componentClass) { + static ImmutableSortedMap extractRoutesFromComponent(Class componentClass) { ImmutableSortedMap.Builder 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) newInstantiator(method)); + Route.create( + action, + (Function) newInstantiator(method), + method.getReturnType()); routes.put(action.path(), route); } return routes.build(); diff --git a/java/google/registry/request/RouterDisplayHelper.java b/java/google/registry/request/RouterDisplayHelper.java new file mode 100644 index 000000000..6161aff99 --- /dev/null +++ b/java/google/registry/request/RouterDisplayHelper.java @@ -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. + * + *

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. + * + *

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: + * + *

    + *
  1. the URL path which maps to this action (with a "(*)" after it if the prefix flag is set) + *
  2. the simple name of the action class + *
  3. the allowable HTTP methods + *
  4. whether to automatically print "ok" in the response + *
  5. whether XSRF protection is enabled + *
  6. the XSRF scope + *
  7. whether login is required + *
  8. the allowable authentication methods + *
  9. the minimum authentication level + *
  10. the user policy + *
+ * + *

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 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 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() + .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() { + @Override + public String apply(Route route) { + return routeToString(route, formatString); + } + }) + .join(Joiner.on(String.format("%n"))); + } +} diff --git a/java/google/registry/tools/BUILD b/java/google/registry/tools/BUILD index b2725773a..c664f8d42 100644 --- a/java/google/registry/tools/BUILD +++ b/java/google/registry/tools/BUILD @@ -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", diff --git a/java/google/registry/tools/GetRoutingMapCommand.java b/java/google/registry/tools/GetRoutingMapCommand.java new file mode 100644 index 000000000..cf9ce8ea2 --- /dev/null +++ b/java/google/registry/tools/GetRoutingMapCommand.java @@ -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))); + } +} diff --git a/java/google/registry/tools/RegistryTool.java b/java/google/registry/tools/RegistryTool.java index a93217aa8..cc8992c58 100644 --- a/java/google/registry/tools/RegistryTool.java +++ b/java/google/registry/tools/RegistryTool.java @@ -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) diff --git a/java/google/registry/util/ResourceUtils.java b/java/google/registry/util/ResourceUtils.java index 096b83363..cbe313d4c 100644 --- a/java/google/registry/util/ResourceUtils.java +++ b/java/google/registry/util/ResourceUtils.java @@ -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) { diff --git a/javatests/google/registry/model/SchemaVersionTest.java b/javatests/google/registry/model/SchemaVersionTest.java index 1750835a2..d57ede042 100644 --- a/javatests/google/registry/model/SchemaVersionTest.java +++ b/javatests/google/registry/model/SchemaVersionTest.java @@ -14,11 +14,10 @@ package google.registry.model; -import static com.google.common.truth.Truth.assert_; -import static google.registry.util.ResourceUtils.readResourceUtf8; +import static com.google.common.io.Resources.getResource; -import com.google.common.base.Joiner; import google.registry.testing.AppEngineRule; +import google.registry.testing.GoldenFileTestHelper; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,28 +31,15 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class SchemaVersionTest { - private static final String GOLDEN_SCHEMA_FILE = "schema.txt"; - - private static final String UPDATE_COMMAND = - "google.registry.tools.RegistryTool -e localhost get_schema " - + ">javatests/google/registry/model/schema.txt"; - - private static final String UPDATE_INSTRUCTIONS = Joiner.on('\n').join( - "", - "-------------------------------------------------------------------------------", - "Your changes affect the Datastore schema. To update the checked-in schema, run:", - UPDATE_COMMAND, - ""); - @Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build(); @Test public void testGoldenSchemaFile() throws Exception { - // Don't use Truth's isEqualTo() because the output is huge and unreadable for large files. - if (!(SchemaVersion.getSchema() - .equals(readResourceUtf8(SchemaVersionTest.class, GOLDEN_SCHEMA_FILE).trim()))) { - assert_().fail(UPDATE_INSTRUCTIONS); - } + GoldenFileTestHelper.testGoldenFile( + SchemaVersion.getSchema(), + getResource(SchemaVersionTest.class, "schema.txt"), + "Datastore schema", + "get_schema"); } } diff --git a/javatests/google/registry/module/backend/BUILD b/javatests/google/registry/module/backend/BUILD index 5b687ea8d..bf27f8ba7 100644 --- a/javatests/google/registry/module/backend/BUILD +++ b/javatests/google/registry/module/backend/BUILD @@ -15,7 +15,10 @@ java_library( ], deps = [ "//java/google/registry/module/backend", + "//java/google/registry/request", + "//java/google/registry/util", "//javatests/google/registry/testing", + "@com_google_guava", "@com_google_truth", "@javax_servlet_api", "@junit", diff --git a/javatests/google/registry/module/backend/BackendRequestComponentTest.java b/javatests/google/registry/module/backend/BackendRequestComponentTest.java new file mode 100644 index 000000000..4fb7a29c3 --- /dev/null +++ b/javatests/google/registry/module/backend/BackendRequestComponentTest.java @@ -0,0 +1,37 @@ +// 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.module.backend; + +import static com.google.common.io.Resources.getResource; + +import google.registry.request.RouterDisplayHelper; +import google.registry.testing.GoldenFileTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link BackendRequestComponent}. */ +@RunWith(JUnit4.class) +public class BackendRequestComponentTest { + + @Test + public void testRoutingMap() throws Exception { + GoldenFileTestHelper.testGoldenFile( + RouterDisplayHelper.extractHumanReadableRoutesFromComponent(BackendRequestComponent.class), + getResource(BackendRequestComponentTest.class, "testdata/backend_routing.txt"), + "backend routing map", + "get_routing_map -c " + BackendRequestComponent.class.getName()); + } +} diff --git a/javatests/google/registry/module/backend/testdata/backend_routing.txt b/javatests/google/registry/module/backend/testdata/backend_routing.txt new file mode 100644 index 000000000..307c055e8 --- /dev/null +++ b/javatests/google/registry/module/backend/testdata/backend_routing.txt @@ -0,0 +1,38 @@ +PATH CLASS METHODS OK XSRF SCOPE LOGIN AUTH_METHODS MIN USER_POLICY +/_dr/cron/commitLogCheckpoint CommitLogCheckpointAction GET y n app n INTERNAL APP IGNORED +/_dr/cron/commitLogFanout CommitLogFanoutAction GET y n app n INTERNAL APP IGNORED +/_dr/cron/fanout TldFanoutAction GET y n app n INTERNAL APP IGNORED +/_dr/cron/readDnsQueue ReadDnsQueueAction GET y n app n INTERNAL APP IGNORED +/_dr/dnsRefresh RefreshDnsAction GET y n app n INTERNAL APP IGNORED +/_dr/task/brdaCopy BrdaCopyAction POST y n app n INTERNAL APP IGNORED +/_dr/task/checkSnapshot CheckSnapshotAction POST,GET y n app n INTERNAL APP IGNORED +/_dr/task/deleteContactsAndHosts DeleteContactsAndHostsAction GET n n app n INTERNAL APP IGNORED +/_dr/task/deleteOldCommitLogs DeleteOldCommitLogsAction POST y n app n INTERNAL APP IGNORED +/_dr/task/deleteProberData DeleteProberDataAction POST n n app n INTERNAL APP IGNORED +/_dr/task/expandRecurringBillingEvents ExpandRecurringBillingEventsAction GET n n app n INTERNAL APP IGNORED +/_dr/task/exportCommitLogDiff ExportCommitLogDiffAction POST y n app n INTERNAL APP IGNORED +/_dr/task/exportDomainLists ExportDomainListsAction POST n n app n INTERNAL APP IGNORED +/_dr/task/exportReservedTerms ExportReservedTermsAction POST n n app n INTERNAL APP IGNORED +/_dr/task/exportSnapshot ExportSnapshotAction POST y n app n INTERNAL APP IGNORED +/_dr/task/importRdeContacts RdeContactImportAction GET n n app n INTERNAL APP IGNORED +/_dr/task/importRdeDomains RdeDomainImportAction GET n n app n INTERNAL APP IGNORED +/_dr/task/importRdeHosts RdeHostImportAction GET n n app n INTERNAL APP IGNORED +/_dr/task/linkRdeHosts RdeHostLinkAction GET n n app n INTERNAL APP IGNORED +/_dr/task/loadSnapshot LoadSnapshotAction POST n n app n INTERNAL APP IGNORED +/_dr/task/mapreduceEntityCleanup MapreduceEntityCleanupAction GET n n app n INTERNAL APP IGNORED +/_dr/task/metrics MetricsExportAction POST n n app n INTERNAL APP IGNORED +/_dr/task/nordnUpload NordnUploadAction POST y n app n INTERNAL APP IGNORED +/_dr/task/nordnVerify NordnVerifyAction POST y n app n INTERNAL APP IGNORED +/_dr/task/pollBigqueryJob BigqueryPollJobAction GET,POST y n app n INTERNAL APP IGNORED +/_dr/task/publishDnsUpdates PublishDnsUpdatesAction POST y n app n INTERNAL APP IGNORED +/_dr/task/rdeReport RdeReportAction POST n n app n INTERNAL APP IGNORED +/_dr/task/rdeStaging RdeStagingAction GET,POST n n app n INTERNAL,API APP ADMIN +/_dr/task/rdeUpload RdeUploadAction POST n n app n INTERNAL APP IGNORED +/_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction GET n n app n INTERNAL APP IGNORED +/_dr/task/syncGroupMembers SyncGroupMembersAction POST n n app n INTERNAL APP IGNORED +/_dr/task/syncRegistrarsSheet SyncRegistrarsSheetAction POST n n app n INTERNAL APP IGNORED +/_dr/task/tmchCrl TmchCrlAction POST y n app n INTERNAL APP IGNORED +/_dr/task/tmchDnl TmchDnlAction POST y n app n INTERNAL APP IGNORED +/_dr/task/tmchSmdrl TmchSmdrlAction POST y n app n INTERNAL APP IGNORED +/_dr/task/updateSnapshotView UpdateSnapshotViewAction POST n n app n INTERNAL APP IGNORED +/_dr/task/verifyEntityIntegrity VerifyEntityIntegrityAction POST n n app n INTERNAL APP IGNORED diff --git a/javatests/google/registry/module/frontend/BUILD b/javatests/google/registry/module/frontend/BUILD index 4a041feba..3a164bedf 100644 --- a/javatests/google/registry/module/frontend/BUILD +++ b/javatests/google/registry/module/frontend/BUILD @@ -15,7 +15,9 @@ java_library( ], deps = [ "//java/google/registry/module/frontend", + "//java/google/registry/request", "//javatests/google/registry/testing", + "@com_google_guava", "@com_google_truth", "@javax_servlet_api", "@junit", diff --git a/javatests/google/registry/module/frontend/FrontendRequestComponentTest.java b/javatests/google/registry/module/frontend/FrontendRequestComponentTest.java new file mode 100644 index 000000000..58070c2a7 --- /dev/null +++ b/javatests/google/registry/module/frontend/FrontendRequestComponentTest.java @@ -0,0 +1,37 @@ +// 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.module.frontend; + +import static com.google.common.io.Resources.getResource; + +import google.registry.request.RouterDisplayHelper; +import google.registry.testing.GoldenFileTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link FrontendRequestComponent}. */ +@RunWith(JUnit4.class) +public class FrontendRequestComponentTest { + + @Test + public void testRoutingMap() throws Exception { + GoldenFileTestHelper.testGoldenFile( + RouterDisplayHelper.extractHumanReadableRoutesFromComponent(FrontendRequestComponent.class), + getResource(FrontendRequestComponentTest.class, "testdata/frontend_routing.txt"), + "frontend routing map", + "get_routing_map -c " + FrontendRequestComponent.class.getName()); + } +} diff --git a/javatests/google/registry/module/frontend/testdata/frontend_routing.txt b/javatests/google/registry/module/frontend/testdata/frontend_routing.txt new file mode 100644 index 000000000..d598408f5 --- /dev/null +++ b/javatests/google/registry/module/frontend/testdata/frontend_routing.txt @@ -0,0 +1,19 @@ +PATH CLASS METHODS OK XSRF SCOPE LOGIN AUTH_METHODS MIN USER_POLICY +/_dr/epp EppTlsAction POST n n app n INTERNAL,API APP ADMIN +/_dr/whois WhoisServer POST n n app n INTERNAL,API APP ADMIN +/check CheckApiAction GET n n app n INTERNAL NONE PUBLIC +/rdap/autnum/(*) RdapAutnumAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/rdap/domain/(*) RdapDomainAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/rdap/domains RdapDomainSearchAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/rdap/entities RdapEntitySearchAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/rdap/entity/(*) RdapEntityAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/rdap/help(*) RdapHelpAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/rdap/ip/(*) RdapIpAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/rdap/nameserver/(*) RdapNameserverAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/rdap/nameservers RdapNameserverSearchAction GET,HEAD n n app n INTERNAL NONE PUBLIC +/registrar ConsoleUiAction GET n n app y INTERNAL,API,LEGACY NONE PUBLIC +/registrar-payment RegistrarPaymentAction POST n y console y INTERNAL,API,LEGACY USER PUBLIC +/registrar-payment-setup RegistrarPaymentSetupAction POST n y console y INTERNAL,API,LEGACY USER PUBLIC +/registrar-settings RegistrarSettingsAction POST n y console y INTERNAL,API,LEGACY USER PUBLIC +/registrar-xhr EppConsoleAction POST n y console n INTERNAL,API,LEGACY USER PUBLIC +/whois/(*) WhoisHttpServer GET n n app n INTERNAL NONE PUBLIC diff --git a/javatests/google/registry/module/tools/BUILD b/javatests/google/registry/module/tools/BUILD index 1b6ef6686..a380296cb 100644 --- a/javatests/google/registry/module/tools/BUILD +++ b/javatests/google/registry/module/tools/BUILD @@ -15,6 +15,9 @@ java_library( ], deps = [ "//java/google/registry/module/tools", + "//java/google/registry/request", + "//javatests/google/registry/testing", + "@com_google_guava", "@com_google_truth", "@javax_servlet_api", "@junit", diff --git a/javatests/google/registry/module/tools/ToolsRequestComponentTest.java b/javatests/google/registry/module/tools/ToolsRequestComponentTest.java new file mode 100644 index 000000000..12c6ce63a --- /dev/null +++ b/javatests/google/registry/module/tools/ToolsRequestComponentTest.java @@ -0,0 +1,37 @@ +// 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.module.tools; + +import static com.google.common.io.Resources.getResource; + +import google.registry.request.RouterDisplayHelper; +import google.registry.testing.GoldenFileTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link ToolsRequestComponent}. */ +@RunWith(JUnit4.class) +public class ToolsRequestComponentTest { + + @Test + public void testRoutingMap() throws Exception { + GoldenFileTestHelper.testGoldenFile( + RouterDisplayHelper.extractHumanReadableRoutesFromComponent(ToolsRequestComponent.class), + getResource(ToolsRequestComponentTest.class, "testdata/tools_routing.txt"), + "tools routing map", + "get_routing_map -c " + ToolsRequestComponent.class.getName()); + } +} diff --git a/javatests/google/registry/module/tools/testdata/tools_routing.txt b/javatests/google/registry/module/tools/testdata/tools_routing.txt new file mode 100644 index 000000000..31d9aa08b --- /dev/null +++ b/javatests/google/registry/module/tools/testdata/tools_routing.txt @@ -0,0 +1,21 @@ +PATH CLASS METHODS OK XSRF SCOPE LOGIN AUTH_METHODS MIN USER_POLICY +/_dr/admin/createGroups CreateGroupsAction POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/createPremiumList CreatePremiumListAction POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/deleteEntity DeleteEntityAction GET n n app n INTERNAL,API APP ADMIN +/_dr/admin/list/domains ListDomainsAction GET,POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/list/hosts ListHostsAction GET,POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/list/premiumLists ListPremiumListsAction GET,POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/list/registrars ListRegistrarsAction GET,POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/list/reservedLists ListReservedListsAction GET,POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/list/tlds ListTldsAction GET,POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/updatePremiumList UpdatePremiumListAction POST n n app n INTERNAL,API APP ADMIN +/_dr/admin/verifyOte VerifyOteAction POST n y admin n INTERNAL,API APP ADMIN +/_dr/epptool EppToolAction POST n y admin n INTERNAL,API APP ADMIN +/_dr/loadtest LoadTestAction POST y n app n INTERNAL APP IGNORED +/_dr/publishDetailReport PublishDetailReportAction POST n y admin n INTERNAL,API APP ADMIN +/_dr/task/generateZoneFiles GenerateZoneFilesAction POST n n app n INTERNAL,API APP ADMIN +/_dr/task/killAllCommitLogs KillAllCommitLogsAction POST n n app n INTERNAL APP IGNORED +/_dr/task/killAllEppResources KillAllEppResourcesAction POST n n app n INTERNAL APP IGNORED +/_dr/task/refreshAllDomains RefreshAllDomainsAction GET n n app n INTERNAL APP IGNORED +/_dr/task/resaveAllEppResources ResaveAllEppResourcesAction GET n n app n INTERNAL APP IGNORED +/_dr/task/restoreCommitLogs RestoreCommitLogsAction POST y n app n INTERNAL,API APP ADMIN diff --git a/javatests/google/registry/testing/GoldenFileTestHelper.java b/javatests/google/registry/testing/GoldenFileTestHelper.java new file mode 100644 index 000000000..60c1e67c4 --- /dev/null +++ b/javatests/google/registry/testing/GoldenFileTestHelper.java @@ -0,0 +1,74 @@ +// 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.testing; + +import static com.google.common.truth.Truth.assert_; +import static google.registry.util.ResourceUtils.readResourceUtf8; + +import com.google.common.base.Joiner; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Helper class to compare a string against a golden file and print out update instructions if + * necessary. + */ +public class GoldenFileTestHelper { + + private static final String UPDATE_COMMAND = + "google.registry.tools.RegistryTool -e localhost %1$s >javatests%2$s"; + + private static final String UPDATE_INSTRUCTIONS = + Joiner.on('\n') + .join( + "", + "-------------------------------------------------------------------------------", + "Your changes affect the %3$s. To update the checked-in version, run:", + UPDATE_COMMAND, + ""); + + private static String getPathProper(URL url) throws MalformedURLException { + String protocol = url.getProtocol(); + if (protocol.equals("jar")) { + url = new URL(url.getPath()); + protocol = url.getProtocol(); + } + if (protocol.equals("file")) { + String[] components = url.getPath().split("!"); + if (components.length >= 2) { + return components[1]; + } + } + return url.getPath(); + } + + public static void testGoldenFile( + String actualValue, + URL goldenFileUrl, + String goldenFileDescription, + String nomulusCommand) + throws Exception { + // Don't use Truth's isEqualTo() because the output is huge and unreadable for large files. + if (!actualValue.equals(readResourceUtf8(goldenFileUrl).trim())) { + assert_() + .fail( + String.format( + UPDATE_INSTRUCTIONS, + nomulusCommand, + getPathProper(goldenFileUrl), + goldenFileDescription)); + } + } +}