diff --git a/java/google/registry/config/RegistryConfig.java b/java/google/registry/config/RegistryConfig.java index 726949248..65f9883d5 100644 --- a/java/google/registry/config/RegistryConfig.java +++ b/java/google/registry/config/RegistryConfig.java @@ -24,10 +24,8 @@ import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.net.HostAndPort; import dagger.Module; import dagger.Provides; -import google.registry.config.RegistryConfigSettings.AppEngine.ToolsServiceUrl; import google.registry.util.RandomStringGenerator; import google.registry.util.StringGenerator; import google.registry.util.TaskQueueUtils; @@ -1275,7 +1273,7 @@ public final class RegistryConfig { @Config("insecureRandom") public static Random provideInsecureRandom() { return new Random(); - }; + } /** Returns a singleton secure random number generator this is slow. */ @Singleton @@ -1351,14 +1349,44 @@ public final class RegistryConfig { return Duration.standardDays(30); } + public static boolean areServersLocal() { + return CONFIG_SETTINGS.get().appEngine.isLocal; + } + /** - * Returns the address of the Nomulus app HTTP server. + * Returns the address of the Nomulus app default HTTP server. * *

This is used by the {@code nomulus} tool to connect to the App Engine remote API. */ - public static HostAndPort getServer() { - ToolsServiceUrl url = CONFIG_SETTINGS.get().appEngine.toolsServiceUrl; - return HostAndPort.fromParts(url.hostName, url.port); + public static URL getDefaultServer() { + return makeUrl(CONFIG_SETTINGS.get().appEngine.defaultServiceUrl); + } + + /** + * Returns the address of the Nomulus app backend HTTP server. + * + *

This is used by the {@code nomulus} tool to connect to the App Engine remote API. + */ + public static URL getBackendServer() { + return makeUrl(CONFIG_SETTINGS.get().appEngine.backendServiceUrl); + } + + /** + * Returns the address of the Nomulus app tools HTTP server. + * + *

This is used by the {@code nomulus} tool to connect to the App Engine remote API. + */ + public static URL getToolsServer() { + return makeUrl(CONFIG_SETTINGS.get().appEngine.toolsServiceUrl); + } + + /** + * Returns the address of the Nomulus app pubapi HTTP server. + * + *

This is used by the {@code nomulus} tool to connect to the App Engine remote API. + */ + public static URL getPubapiServer() { + return makeUrl(CONFIG_SETTINGS.get().appEngine.pubapiServiceUrl); } /** Returns the amount of time a singleton should be cached, before expiring. */ @@ -1466,7 +1494,7 @@ public final class RegistryConfig { * change the contents of the YAML config files. */ @VisibleForTesting - static final Supplier CONFIG_SETTINGS = + public static final Supplier CONFIG_SETTINGS = memoize(YamlUtils::getConfigSettings); private static String formatComments(String text) { diff --git a/java/google/registry/config/RegistryConfigSettings.java b/java/google/registry/config/RegistryConfigSettings.java index f5e23c2b4..58561f0fa 100644 --- a/java/google/registry/config/RegistryConfigSettings.java +++ b/java/google/registry/config/RegistryConfigSettings.java @@ -40,13 +40,11 @@ public class RegistryConfigSettings { /** Configuration options that apply to the entire App Engine project. */ public static class AppEngine { public String projectId; - public ToolsServiceUrl toolsServiceUrl; - - /** Configuration options for the tools service URL. */ - public static class ToolsServiceUrl { - public String hostName; - public int port; - } + public boolean isLocal; + public String defaultServiceUrl; + public String backendServiceUrl; + public String toolsServiceUrl; + public String pubapiServiceUrl; } /** Configuration options for OAuth settings for authenticating users. */ diff --git a/java/google/registry/config/files/default-config.yaml b/java/google/registry/config/files/default-config.yaml index d4dc13f43..9c4a37628 100644 --- a/java/google/registry/config/files/default-config.yaml +++ b/java/google/registry/config/files/default-config.yaml @@ -9,10 +9,13 @@ appEngine: # Globally unique App Engine project ID projectId: registry-project-id - # Hostname and port of the tools service for the project. - toolsServiceUrl: - hostName: localhost - port: 443 + # whether to use local/test credentials when connecting to the servers + isLocal: true + # URLs of the services for the project. + defaultServiceUrl: https://localhost + backendServiceUrl: https://localhost + toolsServiceUrl: https://localhost + pubapiServiceUrl: https://localhost gSuite: # Publicly accessible domain name of the running G Suite instance. diff --git a/java/google/registry/config/files/nomulus-config-production-sample.yaml b/java/google/registry/config/files/nomulus-config-production-sample.yaml index 01a051f7c..9d2e9ca44 100644 --- a/java/google/registry/config/files/nomulus-config-production-sample.yaml +++ b/java/google/registry/config/files/nomulus-config-production-sample.yaml @@ -4,11 +4,14 @@ appEngine: projectId: placeholder - # The "tools-dot-" prefix is used on the project ID in this URL in order to - # get around an issue with double-wildcard SSL certs. - toolsServiceUrl: - hostName: tools-dot-placeholder.appspot.com - port: 443 + # Set to true if running against local servers (localhost) + isLocal: false + # The "-dot-" prefix is used on the project ID in this URL in order + # to get around an issue with double-wildcard SSL certs. + defaultServiceUrl: https://domain-registry-placeholder.appspot.com + backendServiceUrl: https://backend-dot-domain-registry-placeholder.appspot.com + toolsServiceUrl: https://tools-dot-domain-registry-placeholder.appspot.com + pubapiServiceUrl: https://pubapi-dot-domain-registry-placeholder.appspot.com gSuite: domainName: placeholder diff --git a/java/google/registry/tools/AppEngineConnection.java b/java/google/registry/tools/AppEngineConnection.java index cf4393a02..68ab47ddb 100644 --- a/java/google/registry/tools/AppEngineConnection.java +++ b/java/google/registry/tools/AppEngineConnection.java @@ -15,7 +15,6 @@ package google.registry.tools; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Suppliers.memoize; import static com.google.common.net.HttpHeaders.X_REQUESTED_WITH; import static com.google.common.net.MediaType.JSON_UTF_8; import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX; @@ -27,48 +26,55 @@ import com.google.api.client.http.HttpHeaders; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpRequestFactory; import com.google.api.client.http.HttpResponse; -import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.io.CharStreams; -import com.google.common.net.HostAndPort; import com.google.common.net.MediaType; import com.google.re2j.Matcher; import com.google.re2j.Pattern; -import google.registry.security.XsrfTokenManager; -import google.registry.tools.CommandWithConnection.Connection; +import google.registry.config.RegistryConfig; import java.io.IOException; import java.io.InputStreamReader; +import java.net.URL; import java.util.Map; import javax.annotation.Nullable; import javax.inject.Inject; import org.json.simple.JSONValue; -/** An http connection to the appengine server. */ -class AppEngineConnection implements Connection { +/** + * An http connection to an appengine server. + * + *

By default - connects to the TOOLS service. To create a Connection to another service, call + * the {@link #withService} function. + */ +class AppEngineConnection { /** Pattern to heuristically extract title tag contents in HTML responses. */ private static final Pattern HTML_TITLE_TAG_PATTERN = Pattern.compile("(.*?)"); @Inject HttpRequestFactory requestFactory; - @Inject AppEngineConnectionFlags flags; - @Inject XsrfTokenManager xsrfTokenManager; + private final Service service; @Inject - AppEngineConnection() {} + AppEngineConnection() { + service = Service.TOOLS; + } - /** - * Memoized XSRF security token. - * - *

Computing this is expensive since it needs to load {@code ServerSecret} so do it once. - */ - private final Supplier xsrfToken = - memoize(() -> xsrfTokenManager.generateToken(getUserId())); + private AppEngineConnection(Service service, HttpRequestFactory requestFactory) { + this.service = service; + this.requestFactory = requestFactory; + } - @Override - public void prefetchXsrfToken() { - // Cause XSRF token to be fetched, and then stay resident in cache (since it's memoized). - xsrfToken.get(); + enum Service { + DEFAULT, + TOOLS, + BACKEND, + PUBAPI + } + + /** Returns a copy of this connection that talks to a different service. */ + public AppEngineConnection withService(Service service) { + return new AppEngineConnection(service, requestFactory); } /** Returns the contents of the title tag in the given HTML, or null if not found. */ @@ -85,7 +91,8 @@ class AppEngineConnection implements Connection { private String internalSend( String endpoint, Map params, MediaType contentType, @Nullable byte[] payload) throws IOException { - GenericUrl url = new GenericUrl(String.format("%s%s", getServerUrl(), endpoint)); + GenericUrl url = new GenericUrl(getServer()); + url.setRawPath(endpoint); url.putAll(params); HttpRequest request = (payload != null) @@ -120,23 +127,20 @@ class AppEngineConnection implements Connection { } } - // TODO(b/111123862): Rename this to sendPostRequest() - @Override - public String send(String endpoint, Map params, MediaType contentType, byte[] payload) + public String sendPostRequest( + String endpoint, Map params, MediaType contentType, byte[] payload) throws IOException { return internalSend(endpoint, params, contentType, checkNotNull(payload, "payload")); } - @Override public String sendGetRequest(String endpoint, Map params) throws IOException { return internalSend(endpoint, params, MediaType.PLAIN_TEXT_UTF_8, null); } - @Override @SuppressWarnings("unchecked") public Map sendJson(String endpoint, Map object) throws IOException { String response = - send( + sendPostRequest( endpoint, ImmutableMap.of(), JSON_UTF_8, @@ -144,22 +148,17 @@ class AppEngineConnection implements Connection { return (Map) JSONValue.parse(response.substring(JSON_SAFETY_PREFIX.length())); } - @Override - public String getServerUrl() { - return (isLocalhost() ? "http://" : "https://") + getServer().toString(); - } - - HostAndPort getServer() { - return flags.getServer().withDefaultPort(443); // Default to HTTPS port if unspecified. - } - - boolean isLocalhost() { - return flags.getServer().getHost().equals("localhost"); - } - - private String getUserId() { - return isLocalhost() - ? UserIdProvider.getTestUserId() - : UserIdProvider.getProdUserId(); + public URL getServer() { + switch (service) { + case DEFAULT: + return RegistryConfig.getDefaultServer(); + case TOOLS: + return RegistryConfig.getToolsServer(); + case BACKEND: + return RegistryConfig.getBackendServer(); + case PUBAPI: + return RegistryConfig.getPubapiServer(); + } + throw new IllegalStateException("Unknown service: " + service); } } diff --git a/java/google/registry/tools/AppEngineConnectionFlags.java b/java/google/registry/tools/AppEngineConnectionFlags.java deleted file mode 100644 index 020397883..000000000 --- a/java/google/registry/tools/AppEngineConnectionFlags.java +++ /dev/null @@ -1,63 +0,0 @@ -// 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 com.google.common.annotations.VisibleForTesting; -import com.google.common.net.HostAndPort; -import dagger.Module; -import dagger.Provides; -import google.registry.config.RegistryConfig; - -/** - * Class to contain the configuration flags for AppEngineConnection. - * - *

This is broken out into its own class to make it cleaner to extract these from the dagger - * module, where these values are injected. - */ -@Parameters(separators = " =") -class AppEngineConnectionFlags { - - @Parameter(names = "--server", description = "HOST[:PORT] to which remote commands are sent.") - private HostAndPort server = RegistryConfig.getServer(); - - /** Provided for testing. */ - @VisibleForTesting - AppEngineConnectionFlags(HostAndPort server) { - this.server = server; - } - - AppEngineConnectionFlags() {} - - HostAndPort getServer() { - return server; - } - - @Module - static class FlagsModule { - AppEngineConnectionFlags flags; - - FlagsModule(AppEngineConnectionFlags flags) { - this.flags = flags; - } - - @Provides - AppEngineConnectionFlags provideAppEngineConnectionFlags() { - return flags; - } - } -} - diff --git a/java/google/registry/tools/CommandWithConnection.java b/java/google/registry/tools/CommandWithConnection.java index 010afce8f..c53239724 100644 --- a/java/google/registry/tools/CommandWithConnection.java +++ b/java/google/registry/tools/CommandWithConnection.java @@ -14,30 +14,7 @@ package google.registry.tools; -import com.google.common.net.MediaType; -import java.io.IOException; -import java.util.Map; -import javax.annotation.Nullable; - /** A command that can send HTTP requests to a backend module. */ interface CommandWithConnection extends Command { - - /** An http connection to AppEngine. */ - interface Connection { - - void prefetchXsrfToken(); - - /** Send a POST request. TODO(mmuller): change to sendPostRequest() */ - String send( - String endpoint, Map params, MediaType contentType, @Nullable byte[] payload) - throws IOException; - - String sendGetRequest(String endpoint, Map params) throws IOException; - - Map sendJson(String endpoint, Map object) throws IOException; - - String getServerUrl(); - } - - void setConnection(Connection connection); + void setConnection(AppEngineConnection connection); } diff --git a/java/google/registry/tools/CreateOrUpdatePremiumListCommand.java b/java/google/registry/tools/CreateOrUpdatePremiumListCommand.java index 76f14d271..069bbfc68 100644 --- a/java/google/registry/tools/CreateOrUpdatePremiumListCommand.java +++ b/java/google/registry/tools/CreateOrUpdatePremiumListCommand.java @@ -57,11 +57,11 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand required = true) Path inputFile; - protected Connection connection; + protected AppEngineConnection connection; protected int inputLineCount; @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } @@ -101,11 +101,9 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand } // Call the server and get the response data - String response = connection.send( - getCommandPath(), - params.build(), - MediaType.FORM_DATA, - requestBody.getBytes(UTF_8)); + String response = + connection.sendPostRequest( + getCommandPath(), params.build(), MediaType.FORM_DATA, requestBody.getBytes(UTF_8)); return extractServerResponse(response); } diff --git a/java/google/registry/tools/CreateRegistrarCommand.java b/java/google/registry/tools/CreateRegistrarCommand.java index 0eb42e28e..06336b09f 100644 --- a/java/google/registry/tools/CreateRegistrarCommand.java +++ b/java/google/registry/tools/CreateRegistrarCommand.java @@ -50,10 +50,10 @@ final class CreateRegistrarCommand extends CreateOrUpdateRegistrarCommand arity = 1) boolean createGoogleGroups = true; - private Connection connection; + private AppEngineConnection connection; @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } diff --git a/java/google/registry/tools/CreateRegistrarGroupsCommand.java b/java/google/registry/tools/CreateRegistrarGroupsCommand.java index 72c190389..65bfbc133 100644 --- a/java/google/registry/tools/CreateRegistrarGroupsCommand.java +++ b/java/google/registry/tools/CreateRegistrarGroupsCommand.java @@ -41,10 +41,10 @@ public class CreateRegistrarGroupsCommand extends ConfirmingCommand private List registrars = new ArrayList<>(); - private Connection connection; + private AppEngineConnection connection; @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } @@ -66,8 +66,8 @@ public class CreateRegistrarGroupsCommand extends ConfirmingCommand } /** Calls the server endpoint to create groups for the specified registrar client id. */ - static void executeOnServer(Connection connection, String clientId) throws IOException { - connection.send( + static void executeOnServer(AppEngineConnection connection, String clientId) throws IOException { + connection.sendPostRequest( CreateGroupsAction.PATH, ImmutableMap.of(CreateGroupsAction.CLIENT_ID_PARAM, clientId), MediaType.PLAIN_TEXT_UTF_8, @@ -77,7 +77,7 @@ public class CreateRegistrarGroupsCommand extends ConfirmingCommand @Override protected String execute() throws IOException { for (Registrar registrar : registrars) { - connection.send( + connection.sendPostRequest( CreateGroupsAction.PATH, ImmutableMap.of(CreateGroupsAction.CLIENT_ID_PARAM, registrar.getClientId()), MediaType.PLAIN_TEXT_UTF_8, diff --git a/java/google/registry/tools/CurlCommand.java b/java/google/registry/tools/CurlCommand.java index 046a808c7..3804b8d48 100644 --- a/java/google/registry/tools/CurlCommand.java +++ b/java/google/registry/tools/CurlCommand.java @@ -22,11 +22,12 @@ import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.net.MediaType; +import google.registry.tools.AppEngineConnection.Service; import java.util.List; @Parameters(separators = " =", commandDescription = "Send an HTTP command to the nomulus server.") class CurlCommand implements CommandWithConnection { - private Connection connection; + private AppEngineConnection connection; // HTTP Methods that are acceptable for use as values for --method. public enum Method { @@ -62,8 +63,14 @@ class CurlCommand implements CommandWithConnection { + "absent, a GET request is sent.") private List data; + @Parameter( + names = {"--service"}, + description = "Which service to connect to", + required = true) + private Service service; + @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } @@ -77,12 +84,14 @@ class CurlCommand implements CommandWithConnection { throw new IllegalArgumentException("You may not specify a body for a get method."); } - // TODO(b/112315418): Make it possible to address any backend. + AppEngineConnection connectionToService = connection.withService(service); String response = (method == Method.GET) - ? connection.sendGetRequest(path, ImmutableMap.of()) - : connection.send( - path, ImmutableMap.of(), mimeType, + ? connectionToService.sendGetRequest(path, ImmutableMap.of()) + : connectionToService.sendPostRequest( + path, + ImmutableMap.of(), + mimeType, Joiner.on("&").join(data).getBytes(UTF_8)); System.out.println(response); } diff --git a/java/google/registry/tools/DefaultRequestFactoryModule.java b/java/google/registry/tools/DefaultRequestFactoryModule.java index ea2a055c0..4f75c894e 100644 --- a/java/google/registry/tools/DefaultRequestFactoryModule.java +++ b/java/google/registry/tools/DefaultRequestFactoryModule.java @@ -20,6 +20,7 @@ import com.google.api.client.http.javanet.NetHttpTransport; import dagger.Binds; import dagger.Module; import dagger.Provides; +import google.registry.config.RegistryConfig; import javax.inject.Named; import javax.inject.Provider; @@ -43,9 +44,8 @@ class DefaultRequestFactoryModule { @Provides @Named("default") public HttpRequestFactory provideHttpRequestFactory( - AppEngineConnectionFlags connectionFlags, Provider credentialProvider) { - if (connectionFlags.getServer().getHost().equals("localhost")) { + if (RegistryConfig.areServersLocal()) { return new NetHttpTransport() .createRequestFactory( request -> request diff --git a/java/google/registry/tools/EppToolCommand.java b/java/google/registry/tools/EppToolCommand.java index 25d93f1cd..895124cbe 100644 --- a/java/google/registry/tools/EppToolCommand.java +++ b/java/google/registry/tools/EppToolCommand.java @@ -59,7 +59,7 @@ abstract class EppToolCommand extends ConfirmingCommand private List commands = new ArrayList<>(); - private Connection connection; + private AppEngineConnection connection; static class XmlEppParameters { final String clientId; @@ -95,7 +95,7 @@ abstract class EppToolCommand extends ConfirmingCommand } @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } @@ -145,11 +145,13 @@ abstract class EppToolCommand extends ConfirmingCommand params.put("xml", URLEncoder.encode(command.xml, UTF_8.toString())); String requestBody = Joiner.on('&').withKeyValueSeparator("=").join(filterValues(params, Objects::nonNull)); - responses.add(nullToEmpty(connection.send( - "/_dr/epptool", - ImmutableMap.of(), - MediaType.FORM_DATA, - requestBody.getBytes(UTF_8)))); + responses.add( + nullToEmpty( + connection.sendPostRequest( + "/_dr/epptool", + ImmutableMap.of(), + MediaType.FORM_DATA, + requestBody.getBytes(UTF_8)))); } return responses.build(); } diff --git a/java/google/registry/tools/GenerateZoneFilesCommand.java b/java/google/registry/tools/GenerateZoneFilesCommand.java index 1992e405d..19351bc8f 100644 --- a/java/google/registry/tools/GenerateZoneFilesCommand.java +++ b/java/google/registry/tools/GenerateZoneFilesCommand.java @@ -45,10 +45,10 @@ final class GenerateZoneFilesCommand implements CommandWithConnection, CommandWi validateWith = DateParameter.class) private DateTime exportDate = DateTime.now(UTC).minus(standardMinutes(2)).withTimeAtStartOfDay(); - private Connection connection; + private AppEngineConnection connection; @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } @@ -59,10 +59,7 @@ final class GenerateZoneFilesCommand implements CommandWithConnection, CommandWi "tlds", mainParameters, "exportTime", exportDate.toString()); Map response = connection.sendJson(GenerateZoneFilesAction.PATH, params); - System.out.printf( - "Job started at %s%s\n", - connection.getServerUrl(), - response.get("jobPath")); + System.out.printf("Job started at %s %s\n", connection.getServer(), response.get("jobPath")); System.out.println("Output files:"); @SuppressWarnings("unchecked") List filenames = (List) response.get("filenames"); diff --git a/java/google/registry/tools/ListObjectsCommand.java b/java/google/registry/tools/ListObjectsCommand.java index 402af428a..8b670a1c0 100644 --- a/java/google/registry/tools/ListObjectsCommand.java +++ b/java/google/registry/tools/ListObjectsCommand.java @@ -54,10 +54,10 @@ abstract class ListObjectsCommand implements CommandWithConnection, CommandWithR description = "Whether to print full field names in header row (as opposed to aliases)") private boolean fullFieldNames = false; - private Connection connection; + private AppEngineConnection connection; @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } @@ -83,11 +83,9 @@ abstract class ListObjectsCommand implements CommandWithConnection, CommandWithR } params.putAll(getParameterMap()); // Call the server and get the response data. - String response = connection.send( - getCommandPath(), - params.build(), - MediaType.PLAIN_TEXT_UTF_8, - new byte[0]); + String response = + connection.sendPostRequest( + getCommandPath(), params.build(), MediaType.PLAIN_TEXT_UTF_8, new byte[0]); // Parse the returned JSON and make sure it's a map. Object obj = JSONValue.parse(response.substring(JSON_SAFETY_PREFIX.length())); if (!(obj instanceof Map)) { diff --git a/java/google/registry/tools/LoadTestCommand.java b/java/google/registry/tools/LoadTestCommand.java index 4c80540d0..f61b26739 100644 --- a/java/google/registry/tools/LoadTestCommand.java +++ b/java/google/registry/tools/LoadTestCommand.java @@ -77,10 +77,10 @@ class LoadTestCommand extends ConfirmingCommand description = "Time to run the load test in seconds.") int runSeconds = DEFAULT_RUN_SECONDS; - private Connection connection; + private AppEngineConnection connection; @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } @@ -127,10 +127,7 @@ class LoadTestCommand extends ConfirmingCommand .put("runSeconds", runSeconds) .build(); - return connection.send( - LoadTestAction.PATH, - params, - MediaType.PLAIN_TEXT_UTF_8, - new byte[0]); + return connection.sendPostRequest( + LoadTestAction.PATH, params, MediaType.PLAIN_TEXT_UTF_8, new byte[0]); } } diff --git a/java/google/registry/tools/RegistryCli.java b/java/google/registry/tools/RegistryCli.java index 61915f492..2de69bd38 100644 --- a/java/google/registry/tools/RegistryCli.java +++ b/java/google/registry/tools/RegistryCli.java @@ -28,6 +28,7 @@ import com.beust.jcommander.Parameters; import com.beust.jcommander.ParametersDelegate; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; +import google.registry.config.RegistryConfig; import google.registry.model.ofy.ObjectifyService; import google.registry.tools.params.ParameterFactory; import java.security.Security; @@ -53,11 +54,6 @@ final class RegistryCli implements AutoCloseable, CommandRunner { description = "Returns all command names.") private boolean showAllCommands; - // Do not make this final - compile-time constant inlining may interfere with JCommander. - @ParametersDelegate - private AppEngineConnectionFlags appEngineConnectionFlags = - new AppEngineConnectionFlags(); - // Do not make this final - compile-time constant inlining may interfere with JCommander. @ParametersDelegate @@ -84,7 +80,6 @@ final class RegistryCli implements AutoCloseable, CommandRunner { Security.addProvider(new BouncyCastleProvider()); component = DaggerRegistryToolComponent.builder() - .flagsModule(new AppEngineConnectionFlags.FlagsModule(appEngineConnectionFlags)) .build(); } @@ -197,7 +192,7 @@ final class RegistryCli implements AutoCloseable, CommandRunner { RemoteApiOptions options = new RemoteApiOptions(); options.server( getConnection().getServer().getHost(), getConnection().getServer().getPort()); - if (getConnection().isLocalhost()) { + if (RegistryConfig.areServersLocal()) { // Use dev credentials for localhost. options.useDevelopmentServerCredential(); } else { diff --git a/java/google/registry/tools/RegistryToolComponent.java b/java/google/registry/tools/RegistryToolComponent.java index 56a7c14c8..2c8363671 100644 --- a/java/google/registry/tools/RegistryToolComponent.java +++ b/java/google/registry/tools/RegistryToolComponent.java @@ -46,7 +46,6 @@ import javax.inject.Singleton; @Singleton @Component( modules = { - AppEngineConnectionFlags.FlagsModule.class, AppEngineServiceUtilsModule.class, // TODO(b/36866706): Find a way to replace this with a command-line friendly version AuthModule.class, diff --git a/java/google/registry/tools/VerifyOteCommand.java b/java/google/registry/tools/VerifyOteCommand.java index 9a4fb465f..1129c2e7e 100644 --- a/java/google/registry/tools/VerifyOteCommand.java +++ b/java/google/registry/tools/VerifyOteCommand.java @@ -57,10 +57,10 @@ final class VerifyOteCommand implements CommandWithConnection, CommandWithRemote description = "Only show a summary of information") private boolean summarize; - private Connection connection; + private AppEngineConnection connection; @Override - public void setConnection(Connection connection) { + public void setConnection(AppEngineConnection connection) { this.connection = connection; } diff --git a/javatests/google/registry/tools/CreateOrUpdatePremiumListCommandTestCase.java b/javatests/google/registry/tools/CreateOrUpdatePremiumListCommandTestCase.java index a4b8ba84e..cb8f1a7ad 100644 --- a/javatests/google/registry/tools/CreateOrUpdatePremiumListCommandTestCase.java +++ b/javatests/google/registry/tools/CreateOrUpdatePremiumListCommandTestCase.java @@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.io.Files; import com.google.common.net.MediaType; import google.registry.testing.UriParameters; -import google.registry.tools.CommandWithConnection.Connection; import java.io.File; import java.nio.charset.StandardCharsets; import org.mockito.ArgumentCaptor; @@ -46,13 +45,14 @@ public abstract class CreateOrUpdatePremiumListCommandTestCase< } void verifySentParams( - Connection connection, String path, ImmutableMap parameterMap) - throws Exception { - verify(connection).send( - eq(path), - urlParamCaptor.capture(), - eq(MediaType.FORM_DATA), - requestBodyCaptor.capture()); + AppEngineConnection connection, String path, ImmutableMap parameterMap) + throws Exception { + verify(connection) + .sendPostRequest( + eq(path), + urlParamCaptor.capture(), + eq(MediaType.FORM_DATA), + requestBodyCaptor.capture()); assertThat(new ImmutableMap.Builder() .putAll(urlParamCaptor.getValue()) .putAll(UriParameters.parse(new String(requestBodyCaptor.getValue(), UTF_8)).entries()) diff --git a/javatests/google/registry/tools/CreatePremiumListCommandTest.java b/javatests/google/registry/tools/CreatePremiumListCommandTest.java index 9c1ecada6..3a3b136b0 100644 --- a/javatests/google/registry/tools/CreatePremiumListCommandTest.java +++ b/javatests/google/registry/tools/CreatePremiumListCommandTest.java @@ -28,7 +28,6 @@ import com.beust.jcommander.ParameterException; import com.google.common.base.VerifyException; import com.google.common.collect.ImmutableMap; import com.google.common.net.MediaType; -import google.registry.tools.CommandWithConnection.Connection; import google.registry.tools.server.CreatePremiumListAction; import org.junit.Before; import org.junit.Test; @@ -38,8 +37,7 @@ import org.mockito.Mock; public class CreatePremiumListCommandTest extends CreateOrUpdatePremiumListCommandTestCase { - @Mock - Connection connection; + @Mock AppEngineConnection connection; String premiumTermsPath; String premiumTermsCsv; @@ -53,12 +51,12 @@ public class CreatePremiumListCommandTest "example_premium_terms.csv", loadFile(CreatePremiumListCommandTest.class, "example_premium_terms.csv")); servletPath = "/_dr/admin/createPremiumList"; - when(connection.send( - eq(CreatePremiumListAction.PATH), - anyMapOf(String.class, String.class), - any(MediaType.class), - any(byte[].class))) - .thenReturn(JSON_SAFETY_PREFIX + "{\"status\":\"success\",\"lines\":[]}"); + when(connection.sendPostRequest( + eq(CreatePremiumListAction.PATH), + anyMapOf(String.class, String.class), + any(MediaType.class), + any(byte[].class))) + .thenReturn(JSON_SAFETY_PREFIX + "{\"status\":\"success\",\"lines\":[]}"); } @Test @@ -86,13 +84,12 @@ public class CreatePremiumListCommandTest public void testRun_errorResponse() throws Exception { reset(connection); command.setConnection(connection); - when(connection.send( - eq(CreatePremiumListAction.PATH), - anyMapOf(String.class, String.class), - any(MediaType.class), - any(byte[].class))) - .thenReturn( - JSON_SAFETY_PREFIX + "{\"status\":\"error\",\"error\":\"foo already exists\"}"); + when(connection.sendPostRequest( + eq(CreatePremiumListAction.PATH), + anyMapOf(String.class, String.class), + any(MediaType.class), + any(byte[].class))) + .thenReturn(JSON_SAFETY_PREFIX + "{\"status\":\"error\",\"error\":\"foo already exists\"}"); VerifyException thrown = assertThrows( VerifyException.class, () -> runCommandForced("-i=" + premiumTermsPath, "-n=foo")); diff --git a/javatests/google/registry/tools/CreateRegistrarCommandTest.java b/javatests/google/registry/tools/CreateRegistrarCommandTest.java index f6f278bbc..36fc23878 100644 --- a/javatests/google/registry/tools/CreateRegistrarCommandTest.java +++ b/javatests/google/registry/tools/CreateRegistrarCommandTest.java @@ -34,7 +34,6 @@ import com.google.common.collect.Range; import com.google.common.net.MediaType; import google.registry.model.registrar.Registrar; import google.registry.testing.CertificateSamples; -import google.registry.tools.CommandWithConnection.Connection; import java.io.IOException; import java.util.Optional; import org.joda.money.CurrencyUnit; @@ -47,8 +46,7 @@ import org.mockito.Mockito; /** Unit tests for {@link CreateRegistrarCommand}. */ public class CreateRegistrarCommandTest extends CommandTestCase { - @Mock - private Connection connection; + @Mock private AppEngineConnection connection; @Before public void init() { @@ -93,11 +91,12 @@ public class CreateRegistrarCommandTest extends CommandTestCase { - @Mock - private Connection connection; + @Mock private AppEngineConnection connection; @Before public void init() { @@ -41,16 +39,18 @@ public class CreateRegistrarGroupsCommandTest extends @Test public void test_createGroupsForTwoRegistrars() throws Exception { runCommandForced("NewRegistrar", "TheRegistrar"); - verify(connection).send( - eq("/_dr/admin/createGroups"), - eq(ImmutableMap.of("clientId", "NewRegistrar")), - eq(MediaType.PLAIN_TEXT_UTF_8), - eq(new byte[0])); - verify(connection).send( - eq("/_dr/admin/createGroups"), - eq(ImmutableMap.of("clientId", "TheRegistrar")), - eq(MediaType.PLAIN_TEXT_UTF_8), - eq(new byte[0])); + verify(connection) + .sendPostRequest( + eq("/_dr/admin/createGroups"), + eq(ImmutableMap.of("clientId", "NewRegistrar")), + eq(MediaType.PLAIN_TEXT_UTF_8), + eq(new byte[0])); + verify(connection) + .sendPostRequest( + eq("/_dr/admin/createGroups"), + eq(ImmutableMap.of("clientId", "TheRegistrar")), + eq(MediaType.PLAIN_TEXT_UTF_8), + eq(new byte[0])); assertInStdout("Success!"); } diff --git a/javatests/google/registry/tools/CurlCommandTest.java b/javatests/google/registry/tools/CurlCommandTest.java index 35baa0057..84144524d 100644 --- a/javatests/google/registry/tools/CurlCommandTest.java +++ b/javatests/google/registry/tools/CurlCommandTest.java @@ -16,13 +16,19 @@ package google.registry.tools; import static com.google.common.truth.Truth.assertThat; import static google.registry.testing.JUnitBackports.assertThrows; +import static google.registry.tools.AppEngineConnection.Service.BACKEND; +import static google.registry.tools.AppEngineConnection.Service.DEFAULT; +import static google.registry.tools.AppEngineConnection.Service.PUBAPI; +import static google.registry.tools.AppEngineConnection.Service.TOOLS; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableMap; import com.google.common.net.MediaType; -import google.registry.tools.CommandWithConnection.Connection; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -31,34 +37,42 @@ import org.mockito.Mock; /** Unit tests for {@link RefreshDnsForAllDomainsCommand}. */ public class CurlCommandTest extends CommandTestCase { - @Mock private Connection connection; + @Mock private AppEngineConnection connection; + @Mock private AppEngineConnection connectionForService; @Before public void init() { command.setConnection(connection); + when(connection.withService(any())).thenReturn(connectionForService); } @Captor ArgumentCaptor> urlParamCaptor; @Test public void testGetInvocation() throws Exception { - runCommand("--path=/foo/bar?a=1&b=2"); - verify(connection) + runCommand("--path=/foo/bar?a=1&b=2", "--service=TOOLS"); + verify(connection).withService(TOOLS); + verifyNoMoreInteractions(connection); + verify(connectionForService) .sendGetRequest(eq("/foo/bar?a=1&b=2"), eq(ImmutableMap.of())); } @Test public void testExplicitGetInvocation() throws Exception { - runCommand("--path=/foo/bar?a=1&b=2", "--request=GET"); - verify(connection) + runCommand("--path=/foo/bar?a=1&b=2", "--request=GET", "--service=BACKEND"); + verify(connection).withService(BACKEND); + verifyNoMoreInteractions(connection); + verify(connectionForService) .sendGetRequest(eq("/foo/bar?a=1&b=2"), eq(ImmutableMap.of())); } @Test public void testPostInvocation() throws Exception { - runCommand("--path=/foo/bar?a=1&b=2", "--data=some data"); - verify(connection) - .send( + runCommand("--path=/foo/bar?a=1&b=2", "--data=some data", "--service=DEFAULT"); + verify(connection).withService(DEFAULT); + verifyNoMoreInteractions(connection); + verify(connectionForService) + .sendPostRequest( eq("/foo/bar?a=1&b=2"), eq(ImmutableMap.of()), eq(MediaType.PLAIN_TEXT_UTF_8), @@ -67,9 +81,12 @@ public class CurlCommandTest extends CommandTestCase { @Test public void testMultiDataPost() throws Exception { - runCommand("--path=/foo/bar?a=1&b=2", "--data=first=100", "-d", "second=200"); - verify(connection) - .send( + runCommand( + "--path=/foo/bar?a=1&b=2", "--data=first=100", "-d", "second=200", "--service=PUBAPI"); + verify(connection).withService(PUBAPI); + verifyNoMoreInteractions(connection); + verify(connectionForService) + .sendPostRequest( eq("/foo/bar?a=1&b=2"), eq(ImmutableMap.of()), eq(MediaType.PLAIN_TEXT_UTF_8), @@ -78,9 +95,11 @@ public class CurlCommandTest extends CommandTestCase { @Test public void testExplicitPostInvocation() throws Exception { - runCommand("--path=/foo/bar?a=1&b=2", "--request=POST"); - verify(connection) - .send( + runCommand("--path=/foo/bar?a=1&b=2", "--request=POST", "--service=TOOLS"); + verify(connection).withService(TOOLS); + verifyNoMoreInteractions(connection); + verify(connectionForService) + .sendPostRequest( eq("/foo/bar?a=1&b=2"), eq(ImmutableMap.of()), eq(MediaType.PLAIN_TEXT_UTF_8), @@ -94,7 +113,10 @@ public class CurlCommandTest extends CommandTestCase { IllegalArgumentException.class, () -> runCommand( - "--path=/foo/bar?a=1&b=2", "--request=GET", "--data=inappropriate data")); + "--path=/foo/bar?a=1&b=2", + "--request=GET", + "--data=inappropriate data", + "--service=TOOLS")); assertThat(thrown).hasMessageThat().contains("You may not specify a body for a get method."); } } diff --git a/javatests/google/registry/tools/DefaultRequestFactoryModuleTest.java b/javatests/google/registry/tools/DefaultRequestFactoryModuleTest.java index 3a8d21ef0..e6ee2eff5 100644 --- a/javatests/google/registry/tools/DefaultRequestFactoryModuleTest.java +++ b/javatests/google/registry/tools/DefaultRequestFactoryModuleTest.java @@ -20,7 +20,7 @@ import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpRequestFactory; import com.google.api.client.http.HttpRequestInitializer; -import com.google.common.net.HostAndPort; +import google.registry.config.RegistryConfig; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,10 +50,8 @@ public class DefaultRequestFactoryModuleTest { @Test public void test_provideHttpRequestFactory_localhost() { // Make sure that localhost creates a request factory with an initializer. - HttpRequestFactory factory = - module.provideHttpRequestFactory( - new AppEngineConnectionFlags(HostAndPort.fromParts("localhost", 1000)), - () -> FAKE_CREDENTIAL); + RegistryConfig.CONFIG_SETTINGS.get().appEngine.isLocal = true; + HttpRequestFactory factory = module.provideHttpRequestFactory(() -> FAKE_CREDENTIAL); HttpRequestInitializer initializer = factory.getInitializer(); assertThat(initializer).isNotNull(); assertThat(initializer).isNotSameAs(FAKE_CREDENTIAL); @@ -62,11 +60,8 @@ public class DefaultRequestFactoryModuleTest { @Test public void test_provideHttpRequestFactory_remote() { // Make sure that example.com creates a request factory with the UNITTEST client id but no - // initializer. - HttpRequestFactory factory = - module.provideHttpRequestFactory( - new AppEngineConnectionFlags(HostAndPort.fromParts("example.com", 1000)), - () -> FAKE_CREDENTIAL); + RegistryConfig.CONFIG_SETTINGS.get().appEngine.isLocal = false; + HttpRequestFactory factory = module.provideHttpRequestFactory(() -> FAKE_CREDENTIAL); assertThat(factory.getInitializer()).isSameAs(FAKE_CREDENTIAL); } } diff --git a/javatests/google/registry/tools/EppToolVerifier.java b/javatests/google/registry/tools/EppToolVerifier.java index 7e912c148..03cfc5d08 100644 --- a/javatests/google/registry/tools/EppToolVerifier.java +++ b/javatests/google/registry/tools/EppToolVerifier.java @@ -28,7 +28,6 @@ import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.net.MediaType; -import google.registry.tools.CommandWithConnection.Connection; import google.registry.tools.server.ToolsTestData; import java.net.URLDecoder; import java.util.Map; @@ -49,7 +48,7 @@ import org.mockito.ArgumentCaptor; */ public class EppToolVerifier { - private final Connection connection = mock(Connection.class); + private final AppEngineConnection connection = mock(AppEngineConnection.class); private String clientId; private boolean superuser; @@ -167,11 +166,9 @@ public class EppToolVerifier { return; } ArgumentCaptor params = ArgumentCaptor.forClass(byte[].class); - verify(connection, atLeast(0)).send( - eq("/_dr/epptool"), - eq(ImmutableMap.of()), - eq(MediaType.FORM_DATA), - params.capture()); + verify(connection, atLeast(0)) + .sendPostRequest( + eq("/_dr/epptool"), eq(ImmutableMap.of()), eq(MediaType.FORM_DATA), params.capture()); capturedParams = ImmutableList.copyOf(params.getAllValues()); paramIndex = 0; } @@ -198,7 +195,7 @@ public class EppToolVerifier { } /** Returns the (mock) Connection that is being monitored by this verifier. */ - private Connection getConnection() { + private AppEngineConnection getConnection() { return connection; } } diff --git a/javatests/google/registry/tools/ListDomainsCommandTest.java b/javatests/google/registry/tools/ListDomainsCommandTest.java index cd5ea579a..f5576bad1 100644 --- a/javatests/google/registry/tools/ListDomainsCommandTest.java +++ b/javatests/google/registry/tools/ListDomainsCommandTest.java @@ -60,7 +60,7 @@ public class ListDomainsCommandTest extends ListObjectsCommandTestCase extends CommandTestCase { - @Mock Connection connection; + @Mock AppEngineConnection connection; /** Where to find the servlet task; set by the subclass. */ abstract String getTaskPath(); @@ -62,7 +61,7 @@ public abstract class ListObjectsCommandTestCase .collect(toImmutableList()); } command.setConnection(connection); - when(connection.send( + when(connection.sendPostRequest( eq(getTaskPath()), anyMapOf(String.class, Object.class), eq(MediaType.PLAIN_TEXT_UTF_8), @@ -82,7 +81,7 @@ public abstract class ListObjectsCommandTestCase fullFieldNames.ifPresent(aBoolean -> params.put(FULL_FIELD_NAMES_PARAM, aBoolean)); params.putAll(getOtherParameters()); verify(connection) - .send( + .sendPostRequest( eq(getTaskPath()), eq(params.build()), eq(MediaType.PLAIN_TEXT_UTF_8), eq(new byte[0])); } diff --git a/javatests/google/registry/tools/LoadTestCommandTest.java b/javatests/google/registry/tools/LoadTestCommandTest.java index a4a496563..914939d90 100644 --- a/javatests/google/registry/tools/LoadTestCommandTest.java +++ b/javatests/google/registry/tools/LoadTestCommandTest.java @@ -24,7 +24,6 @@ import static org.mockito.Mockito.verifyZeroInteractions; import com.google.common.collect.ImmutableMap; import com.google.common.net.MediaType; import google.registry.model.registrar.Registrar; -import google.registry.tools.CommandWithConnection.Connection; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,7 +31,7 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class LoadTestCommandTest extends CommandTestCase { - Connection connection = mock(Connection.class); + AppEngineConnection connection = mock(AppEngineConnection.class); @Before public void setUp() { @@ -55,11 +54,9 @@ public class LoadTestCommandTest extends CommandTestCase { .put("contactInfos", 1) .put("runSeconds", 4600) .build(); - verify(connection).send( - eq("/_dr/loadtest"), - eq(parms), - eq(MediaType.PLAIN_TEXT_UTF_8), - eq(new byte[0])); + verify(connection) + .sendPostRequest( + eq("/_dr/loadtest"), eq(parms), eq(MediaType.PLAIN_TEXT_UTF_8), eq(new byte[0])); } @Test @@ -86,11 +83,9 @@ public class LoadTestCommandTest extends CommandTestCase { .put("contactInfos", 15) .put("runSeconds", 16) .build(); - verify(connection).send( - eq("/_dr/loadtest"), - eq(parms), - eq(MediaType.PLAIN_TEXT_UTF_8), - eq(new byte[0])); + verify(connection) + .sendPostRequest( + eq("/_dr/loadtest"), eq(parms), eq(MediaType.PLAIN_TEXT_UTF_8), eq(new byte[0])); } @Test diff --git a/javatests/google/registry/tools/UpdatePremiumListCommandTest.java b/javatests/google/registry/tools/UpdatePremiumListCommandTest.java index d8858547a..2a8b0ba8d 100644 --- a/javatests/google/registry/tools/UpdatePremiumListCommandTest.java +++ b/javatests/google/registry/tools/UpdatePremiumListCommandTest.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableMap; import com.google.common.net.MediaType; -import google.registry.tools.CommandWithConnection.Connection; import google.registry.tools.server.UpdatePremiumListAction; import org.junit.Before; import org.junit.Test; @@ -33,8 +32,7 @@ import org.mockito.Mock; public class UpdatePremiumListCommandTest extends CreateOrUpdatePremiumListCommandTestCase { - @Mock - Connection connection; + @Mock AppEngineConnection connection; String premiumTermsPath; String premiumTermsCsv; @@ -48,12 +46,12 @@ public class UpdatePremiumListCommandTest writeToNamedTmpFile( "example_premium_terms.csv", loadFile(UpdatePremiumListCommandTest.class, "example_premium_terms.csv")); - when(connection.send( - eq(UpdatePremiumListAction.PATH), - anyMapOf(String.class, String.class), - any(MediaType.class), - any(byte[].class))) - .thenReturn(JSON_SAFETY_PREFIX + "{\"status\":\"success\",\"lines\":[]}"); + when(connection.sendPostRequest( + eq(UpdatePremiumListAction.PATH), + anyMapOf(String.class, String.class), + any(MediaType.class), + any(byte[].class))) + .thenReturn(JSON_SAFETY_PREFIX + "{\"status\":\"success\",\"lines\":[]}"); } @Test diff --git a/javatests/google/registry/tools/VerifyOteCommandTest.java b/javatests/google/registry/tools/VerifyOteCommandTest.java index 5c6c2ccc9..39ed997f1 100644 --- a/javatests/google/registry/tools/VerifyOteCommandTest.java +++ b/javatests/google/registry/tools/VerifyOteCommandTest.java @@ -27,7 +27,6 @@ import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import google.registry.model.registrar.Registrar; -import google.registry.tools.CommandWithConnection.Connection; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -35,7 +34,7 @@ import org.mockito.Mock; /** Unit tests for {@link VerifyOteCommand}. */ public class VerifyOteCommandTest extends CommandTestCase { - @Mock private Connection connection; + @Mock private AppEngineConnection connection; @Before public void init() throws Exception {