From 5d8da144d31b7baa45878a571bf4a96b7ed4a397 Mon Sep 17 00:00:00 2001 From: Jason Borg Date: Mon, 29 May 2023 19:48:33 +0000 Subject: [PATCH] chore: Remove Cloud Debugger Backend support. This change removes support for the Cloud Debugger Backend making the Firebase RTDB backend the default. This change also renders the `use_firebase` flag obsolete, though it is kept around to prevent loading failures for invocations still setting it. --- .../google/devtools/cdbg/debuglets/java/BUILD | 16 - .../cdbg/debuglets/java/GcpHubClient.java | 721 ------------------ .../google/devtools/cdbg/debuglets/java/BUILD | 21 - .../cdbg/debuglets/java/GcpHubClientTest.java | 669 ---------------- src/agent/jvmti_globals.cc | 16 +- src/codegen/BUILD | 1 - src/codegen/config.json | 9 - 7 files changed, 6 insertions(+), 1447 deletions(-) delete mode 100644 src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java/GcpHubClient.java delete mode 100644 src/agent/internals/src/test/java/com/google/devtools/cdbg/debuglets/java/GcpHubClientTest.java diff --git a/src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java/BUILD b/src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java/BUILD index 067ef1b3..ad5c63dd 100644 --- a/src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java/BUILD +++ b/src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java/BUILD @@ -65,21 +65,6 @@ java_library( ], ) -java_library( - name = "gcp_hub_client", - srcs = ["GcpHubClient.java"], - deps = [ - ":gcp_debuglet_version", - ":gcp_environment", - ":gcp_metadata", - ":hub_client", - ":labels", - ":logger", - ":mapper", - "@maven//:com_google_code_gson_gson" - ], -) - java_library( name = "gcp_metadata", srcs = [ @@ -176,7 +161,6 @@ java_library( ":gcp_breakpoint_labels_provider", ":gcp_debuglet_version", ":gcp_environment", - ":gcp_hub_client", ":gcp_metadata", ":hub_client", ":labels", diff --git a/src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java/GcpHubClient.java b/src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java/GcpHubClient.java deleted file mode 100644 index b0fab58d..00000000 --- a/src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java/GcpHubClient.java +++ /dev/null @@ -1,721 +0,0 @@ -/** - * Copyright 2015 Google Inc. 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 com.google.devtools.cdbg.debuglets.java; - -import static com.google.devtools.cdbg.debuglets.java.AgentLogger.infofmt; -import static com.google.devtools.cdbg.debuglets.java.AgentLogger.warnfmt; -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.google.gson.JsonSyntaxException; -import com.google.gson.stream.JsonWriter; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.lang.reflect.Type; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.file.Paths; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; - -class GcpHubClient implements HubClient { - /** HTTP request and response of RegisterDebuggee message for GSON deserialization. */ - static class RegisterDebuggeeMessage { - @SuppressWarnings("unused") - static class Debuggee { - private String id; - private String project; - private String uniquifier; - private String description; - private Map labels; - private String agentVersion; - private JsonElement[] sourceContexts; - private Boolean isDisabled; - private String canaryMode; - } - - private Debuggee debuggee = new Debuggee(); - - // The field will be set by the gson serialization, so no need for a setter. - private String agentId = null; - - public void setProject(String project) { - debuggee.project = project; - } - - public void setUniquifier(String uniquifier) { - debuggee.uniquifier = uniquifier; - } - - public void setDescription(String description) { - debuggee.description = description; - } - - public void setLabels(Map labels) { - debuggee.labels = labels; - } - - public void setAgentVersion(String agentVersion) { - debuggee.agentVersion = agentVersion; - } - - public void setSourceContexts(String[] files) { - if (files == null) { - debuggee.sourceContexts = null; - return; - } - - List sourceContextsList = new ArrayList<>(); - for (int i = 0; i < files.length; ++i) { - try { - sourceContextsList.add(JsonParser.parseString(files[i])); - } catch (JsonSyntaxException e) { - warnfmt(e, "Source context file could not be parsed as JSON: %s", files[i]); - continue; - } - } - - debuggee.sourceContexts = sourceContextsList.toArray(new JsonElement[0]); - } - - public void setCanaryMode(String canaryMode) { - debuggee.canaryMode = canaryMode; - } - - public String getDebuggeeId() { - return (debuggee == null) ? null : debuggee.id; - } - - public boolean getIsDisabled() { - if (debuggee == null) { - return false; - } - - if (debuggee.isDisabled == null) { - return false; // Default. - } - - return debuggee.isDisabled; - } - - public String getCanaryMode() { - return (debuggee == null) ? null : debuggee.canaryMode; - } - - public String getAgentId() { - return agentId; - } - } - - /** HTTP response of ListActiveBreakpoints message for GSON deserialization. */ - static class ListActiveBreakpointsResponse { - private String nextWaitToken; - private boolean waitExpired; - private JsonElement[] breakpoints; - - public String getNextWaitToken() { - return nextWaitToken; - } - - public boolean getWaitExpired() { - return waitExpired; - } - - public byte[][] serializeBreakpoints() throws IOException { - if (breakpoints == null) { - return new byte[0][]; - } - - byte[][] serializedBreakpoints = new byte[breakpoints.length][]; - for (int i = 0; i < breakpoints.length; ++i) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - JsonWriter writer = new JsonWriter(new OutputStreamWriter(outputStream, UTF_8)); - gson.toJson(breakpoints[i], writer); - writer.flush(); - serializedBreakpoints[i] = outputStream.toByteArray(); - } - - return serializedBreakpoints; - } - } - - /** - * Helper class to automatically insert and remove connection from {@link - * GcpHubClient#activeConnections}. - */ - private final class ActiveConnection implements AutoCloseable { - private final HttpURLConnection connection; - - public ActiveConnection(HttpURLConnection connection) { - this.connection = connection; - - synchronized (activeConnections) { - if (isShutdown) { - // We don't need to call "disconnect" here. "URL.openConnection" doesn't actually - // establish the connection, so calling "disconnect" will have no effect. - throw new RuntimeException("Shutdown in progress"); - } - - activeConnections.add(this); - } - } - - @Override - public void close() { - synchronized (activeConnections) { - activeConnections.remove(this); - } - } - - public HttpURLConnection get() { - return connection; - } - } - - /** List of labels that (if defined) go into debuggee description. */ - private static final String[] DESCRIPTION_LABELS = - new String[] {Labels.Debuggee.MODULE, Labels.Debuggee.VERSION, Labels.Debuggee.MINOR_VERSION}; - - /** Name of the source context file. */ - private static final String SOURCE_CONTEXT_RESOURCE_NAME = "source-context.json"; - - /** - * Expected name of the git properties file. The file is generated by - * https://github.com/ktoso/maven-git-commit-id-plugin which allows some flexibility in - * configuring file name, keys prefixes etc. We currently support default value only (if file name - * is changed, we don't know what we should look for). - */ - private static final String GIT_PROPERTIES_RESOURCE_NAME = "git.properties"; - - /** - * Locations that will be searched to find the source-context.json file. For each class path entry - * that represents a directory, these paths will be appended to the directory when searching. For - * each class path entry that directly represents a jar file, these paths will be relative to the - * root directory inside the jar file. - */ - private static final String[] SOURCE_CONTEXT_RESOURCE_DIRS = - new String[] { - // The default location for the source context file is anywhere in the class path, or the - // root of a jar that is directly in the classpath. - ".", - - // In some frameworks, the user might put the source context file to a place not in the - // class path or not in the root of the deploy jar. Extending the search of source context - // to these additional directories should cover most such cases. - "./WEB-INF/classes", - "./META-INF/classes", - "./BOOT-INF/classes" - }; - - /** - * JSON serialization and deserialization. We register a special adapter for {@link JsonElement} - * to bring whole chunks of JSON we don't bother to define a schema. - */ - private static final Gson gson = - new GsonBuilder() - .registerTypeAdapter( - JsonElement.class, - new JsonDeserializer() { - @Override - public JsonElement deserialize( - JsonElement json, Type t, JsonDeserializationContext c) { - return json; - } - }) - .registerTypeAdapter( - JsonElement.class, - new JsonSerializer() { - @Override - public JsonElement serialize(JsonElement json, Type t, JsonSerializationContext c) { - return json; - } - }) - .create(); - - /** Base URL of Debuglet Controller service. */ - private URL controllerBaseUrl = null; - - /** GCP project information and access token. */ - private final MetadataQuery metadata; - - /** Read and explore application resources. */ - private final ClassPathLookup classPathLookup; - - /** Debuggee labels (such as version and module) */ - private final Map labels; - - /** Shutdown flag blocking all outgoing HTTP calls to metadata service. */ - private boolean isShutdown = false; - - /** List of active HTTP connections to be closed during shutdown. */ - private final List activeConnections = new ArrayList<>(); - - /** - * Cache of unique identifier of the application resources. Computing uniquifier is an expensive - * operation and we don't want to repeat it on every {@link GcpHubClient#registerDebuggee()} call. - */ - private String uniquifier = null; - - /** - * Cache of source context files embedded into the application. We read these files only once and - * reuse it in every {@link GcpHubClient#registerDebuggee()} call. - */ - private String[] sourceContextFiles = null; - - /** Registered debuggee ID. Use getter/setter to access. */ - private String debuggeeId = "not-registered-yet"; - - /** Registered agent's ID. Use getter/setter to access. */ - private String agentId = ""; - - /** The last wait_token returned in the ListActiveBreakpoints response. */ - private String lastWaitToken = "init"; - - /** Default constructor using environment provided by {@link GcpEnvironment}. */ - public GcpHubClient() { - this.metadata = GcpEnvironment.getMetadataQuery(); - this.classPathLookup = ClassPathLookup.defaultInstance; - this.labels = GcpEnvironment.getDebuggeeLabels(); - } - - /** - * Class constructor - * Visible for testing - * @param controllerBaseUrl base URL of Debuglet Controller service - * @param metadata GCP project information and access token - * @param classPathLookup read and explore application resources - * @param labels debuggee labels (such as version and module) - */ - public GcpHubClient( - URL controllerBaseUrl, - MetadataQuery metadata, - ClassPathLookup classPathLookup, - Map labels) { - this.controllerBaseUrl = controllerBaseUrl; - this.metadata = metadata; - this.classPathLookup = classPathLookup; - this.labels = labels; - } - - @Override - public boolean registerDebuggee(Map extraDebuggeeLabels) throws Exception { - // No point going on if we don't have environment information. - if (metadata.getProjectId().isEmpty() || metadata.getProjectNumber().isEmpty()) { - throw new Exception("Environment not available"); - } - - // Send the request. - RegisterDebuggeeMessage request = getDebuggeeInfo(extraDebuggeeLabels); - JsonElement responseJson; - String errorResponse = ""; - try (ActiveConnection connection = openConnection("debuggees/register")) { - connection.get().setDoOutput(true); - try (Writer writer = new OutputStreamWriter(connection.get().getOutputStream(), UTF_8)) { - gson.toJson(request, writer); - } - - try (Reader reader = new InputStreamReader(connection.get().getInputStream(), UTF_8)) { - responseJson = JsonParser.parseReader(reader); - } catch (IOException e) { - errorResponse = readErrorStream(connection.get()); - throw e; - } - } catch (IOException e) { - warnfmt(e, "Failed to register debuggee %s: %s", gson.toJson(request), errorResponse); - throw e; - } - - RegisterDebuggeeMessage response = gson.fromJson(responseJson, RegisterDebuggeeMessage.class); - if ((response == null) - || (response.getDebuggeeId() == null) - || response.getDebuggeeId().isEmpty()) { - throw new Exception("Bad debuggee"); - } - - if (response.getIsDisabled()) { - infofmt("Debuggee is marked as disabled"); - return false; - } - - setDebuggeeId(response.getDebuggeeId()); - setAgentId(response.getAgentId()); - infofmt( - "Debuggee %s, agentId %s, registered: %s, agent version: %s", - getDebuggeeId(), getAgentId(), responseJson, GcpDebugletVersion.VERSION); - - return true; - } - - @Override - public ListActiveBreakpointsResult listActiveBreakpoints() throws Exception { - StringBuilder path = new StringBuilder(); - path.append("debuggees/"); - path.append(URLEncoder.encode(getDebuggeeId(), UTF_8.name())); - path.append("/breakpoints"); - path.append("?successOnTimeout=true"); - if (lastWaitToken != null) { - path.append("&waitToken="); - path.append(URLEncoder.encode(lastWaitToken, UTF_8.name())); - } - if (getAgentId() != null && !getAgentId().isEmpty()) { - path.append("&agentId="); - path.append(URLEncoder.encode(getAgentId(), UTF_8.name())); - } - - ListActiveBreakpointsResponse response; - String errorResponse = ""; - try (ActiveConnection connection = openConnection(path.toString())) { - try (Reader reader = new InputStreamReader(connection.get().getInputStream(), UTF_8)) { - response = gson.fromJson(reader, ListActiveBreakpointsResponse.class); - } catch (IOException e) { - errorResponse = readErrorStream(connection.get()); - throw e; - } - } catch (IOException e) { - warnfmt(e, "Failed to query the list of active breakpoints: %s", errorResponse); - throw e; - } - - if (response.getWaitExpired()) { - return LIST_ACTIVE_BREAKPOINTS_TIMEOUT; - } - - lastWaitToken = response.getNextWaitToken(); - final byte[][] breakpoints = response.serializeBreakpoints(); - - return new ListActiveBreakpointsResult() { - @Override - public boolean getIsTimeout() { - return false; - } - - @Override - public String getFormat() { - return "json"; - } - - @Override - public byte[][] getActiveBreakpoints() { - return breakpoints; - } - }; - } - - @Override - public void transmitBreakpointUpdate(String format, String breakpointId, byte[] breakpoint) - throws Exception { - if (!"json".equals(format)) { - throw new UnsupportedOperationException("GcpHubClient only supports protobuf format"); - } - - String theDebuggeeId = getDebuggeeId(); - String path = - String.format( - "debuggees/%s/breakpoints/%s", - URLEncoder.encode(theDebuggeeId, UTF_8.name()), - URLEncoder.encode(breakpointId, UTF_8.name())); - try (ActiveConnection connection = openConnection(path)) { - // We could parse breakpoint back to JsonObject, then embed it as in the request element - // and serialize everything back. This would be very inefficient, which is important here - // since breakpoint result is fairly large and contains thousands of JSON elements. - connection.get().setDoOutput(true); // Request with body. - connection.get().setRequestMethod("PUT"); - try (OutputStream outputStream = connection.get().getOutputStream()) { - outputStream.write("{\"breakpoint\":".getBytes(UTF_8)); - outputStream.write(breakpoint); - outputStream.write("}".getBytes(UTF_8)); - } - - // Trigger the request to be sent over. We don't really care to read the response. - try { - connection.get().getInputStream().close(); - } catch (IOException e) { - // We always call readErrorStream to close the error stream to avoid socket leak. - String errorResponse = readErrorStream(connection.get()); - int responseCode = connection.get().getResponseCode(); - - // We consider all application errors (5xx) and timeout (408) to be transient errors - // that can be retried. - boolean isTransientError = ((responseCode >= 500) || (responseCode == 408)); - if (!isTransientError) { - // There is no point in retrying the transmission. It will fail. - warnfmt( - e, - "Failed to transmit breakpoint update, debuggee: %s, breakpoint ID: %s, " - + "response: %s\n%s", - theDebuggeeId, - breakpointId, - connection.get().getResponseMessage(), - errorResponse); - return; - } - - throw e; - } - } - } - - @Override - public void registerBreakpointCanary(String breakpointId) throws Exception { - throw new UnsupportedOperationException( - "GcpHubClient#registerBreakpointCanary not implemented"); - } - - @Override - public void approveBreakpointCanary(String breakpointId) throws Exception { - throw new UnsupportedOperationException("GcpHubClient#approveBreakpointCanary not implemented"); - } - - /** If there is any reason to not enable the debugger, return false here. */ - @Override - public boolean isEnabled() { - return true; - } - - @Override - public void shutdown() { - metadata.shutdown(); - - List connections = new ArrayList<>(); - synchronized (activeConnections) { - isShutdown = true; - connections.addAll(activeConnections); - } - - for (ActiveConnection connection : connections) { - connection.get().disconnect(); - } - } - - public String getDebuggeeId() { - return debuggeeId; - } - - private void setDebuggeeId(String id) { - debuggeeId = id; - } - - public String getAgentId() { - return agentId; - } - - private void setAgentId(String id) { - agentId = id; - } - - /** - * Lazily initializes the base URL from GcpEnvironment. If the URL string is a place holder string - * "#", then defer the initialization by throwing an IllegalStateException. Note that the place - * holder "#" is only for testing purposes. - * - * @throws IllegalStateException when Controller Base URL has not initialized - * @throws MalformedURLException when the base URL string does not meet standard URL format - */ - private void requireControllerBaseUrl() throws MalformedURLException { - if (controllerBaseUrl != null) { - return; - } - - String baseUrlString = GcpEnvironment.getControllerBaseUrlString(); - if (baseUrlString.equals("#")) { - throw new IllegalStateException("Controller Base URL not yet set"); - } - controllerBaseUrl = new URL(baseUrlString); - } - - /** - * Fills in the debuggee registration request message. - * - * @param extraDebuggeeLabels Extra labels to include in the Debuggee. These are to be in addition - * to the labels already collected locally that are to be included. - * - * @return debuggee registration request message - */ - private RegisterDebuggeeMessage getDebuggeeInfo(Map extraDebuggeeLabels) - throws NoSuchAlgorithmException, IOException { - String property; - - property = System.getProperty("com.google.cdbg.debuggee.file"); - if ((property != null) && !property.isEmpty()) { - try (InputStream stream = new FileInputStream(property); - Reader reader = new InputStreamReader(stream, UTF_8)) { - // If we got bad JSON, GSON will just throw exception that will fail registerDebuggee call. - return gson.fromJson(reader, RegisterDebuggeeMessage.class); - } - } - - property = System.getProperty("com.google.cdbg.debuggee.json"); - if ((property != null) && !property.isEmpty()) { - // If we got bad JSON, GSON will just throw exception that will fail registerDebuggee call. - return gson.fromJson(property, RegisterDebuggeeMessage.class); - } - - // Read source context files if not done yet. - if (sourceContextFiles == null) { - // Using a set eliminates duplicate source context files (i.e., the same file added twice). - SortedSet resources = new TreeSet<>(); - - for (String sourceContextDir : SOURCE_CONTEXT_RESOURCE_DIRS) { - String sourceContextFilePath = - Paths.get(sourceContextDir, SOURCE_CONTEXT_RESOURCE_NAME).normalize().toString(); - Collections.addAll( - resources, classPathLookup.readApplicationResource(sourceContextFilePath)); - Collections.addAll( - resources, new AppPathLookup().readApplicationResource(sourceContextFilePath)); - } - - // If SOURCE_CONTEXT_RESOURCE_NAME is not found, we try GIT_PROPERTIES_RESOURCE_NAME - // When searching for GIT_PROPERTIES_RESOURCE_NAME file, do not look at AppPathLookup. - if (resources.isEmpty()) { - for (String sourceContextDir : SOURCE_CONTEXT_RESOURCE_DIRS) { - String gitPropertiesFilePath = - Paths.get(sourceContextDir, GIT_PROPERTIES_RESOURCE_NAME).normalize().toString(); - Collections.addAll( - resources, - classPathLookup.readGitPropertiesResourceAsSourceContext(gitPropertiesFilePath)); - } - } - - sourceContextFiles = resources.toArray(new String[0]); - } - - Map allLabels = new TreeMap<>(); - allLabels.putAll(extraDebuggeeLabels); - allLabels.putAll(labels); - - if (uniquifier == null) { - boolean hasSourceContext = ((sourceContextFiles != null) && (sourceContextFiles.length > 0)); - - // Compute uniquifier of debuggee properties. Start with an initial 20B sha-1 hash value. - uniquifier = "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"; - - if (!allLabels.containsKey(Labels.Debuggee.MINOR_VERSION) && !hasSourceContext) { - // There is no source context and minor version. It means that different versions of the - // application may be running with the same debuggee properties. Hash of application - // binaries to generate different debuggees in this case. - uniquifier = classPathLookup.computeDebuggeeUniquifier(uniquifier); - } - } - - // Format the request body. - RegisterDebuggeeMessage request = new RegisterDebuggeeMessage(); - request.setProject(metadata.getProjectNumber()); - request.setUniquifier(uniquifier); - request.setDescription(getDebuggeeDescription()); - request.setLabels(allLabels); - request.setAgentVersion( - String.format("google.com/java-gcp/@%d", GcpDebugletVersion.MAJOR_VERSION)); - request.setSourceContexts(sourceContextFiles); - request.setCanaryMode(GcpEnvironment.getDebuggeeCanaryMode().toString()); - - return request; - } - - /** - * Formats debuggee description based on GCP project metadata and labels. - * - * @return debuggee description - */ - private String getDebuggeeDescription() { - StringBuilder description = new StringBuilder(); - description.append(metadata.getProjectId()); - - // TODO: remove after we completely switch over to structured labels. - if (labels.containsKey(GcpEnvironment.DEBUGGEE_DESCRIPTION_SUFFIX_LABEL)) { - description.append(labels.get(GcpEnvironment.DEBUGGEE_DESCRIPTION_SUFFIX_LABEL)); - return description.toString(); - } - - for (String key : DESCRIPTION_LABELS) { - if (labels.containsKey(key)) { - description.append('-'); - description.append(labels.get(key)); - } - } - - return description.toString(); - } - - /** - * Creates HTTP request to the Debuglet Controller API. - * - * @param path request URI relative to {@link GcpHubClient#controllerBaseUrl} - * @return new HTTP connection - * @throws IOException when URL construction or connection fails - * @throws IllegalStateException when Controller Service Base URL has not initialized - */ - private ActiveConnection openConnection(String path) throws IOException { - requireControllerBaseUrl(); - URL url = new URL(controllerBaseUrl, path); - - ActiveConnection connection = new ActiveConnection((HttpURLConnection) url.openConnection()); - try { - connection.get().setUseCaches(false); - - connection.get().setRequestProperty("Authorization", "Bearer " + metadata.getAccessToken()); - connection.get().setRequestProperty("Content-Type", "application/json"); - - return connection; - } catch (Throwable t) { - connection.close(); - throw t; - } - } - - /** - * Reads error response stream from an HTTP connection. - * - * @param connection failed HTTP connection - * @return error response or empty string if one could not be read - */ - private String readErrorStream(HttpURLConnection connection) { - try (InputStream inputStream = connection.getErrorStream(); - InputStreamReader inputStreamReader = new InputStreamReader(inputStream, UTF_8); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) { - StringBuilder errorResponse = new StringBuilder(); - String line; - while ((line = bufferedReader.readLine()) != null) { - errorResponse.append(line); - errorResponse.append('\n'); - } - - return errorResponse.toString(); - } catch (IOException e) { - return ""; - } - } -} diff --git a/src/agent/internals/src/test/java/com/google/devtools/cdbg/debuglets/java/BUILD b/src/agent/internals/src/test/java/com/google/devtools/cdbg/debuglets/java/BUILD index ab547477..5038a122 100644 --- a/src/agent/internals/src/test/java/com/google/devtools/cdbg/debuglets/java/BUILD +++ b/src/agent/internals/src/test/java/com/google/devtools/cdbg/debuglets/java/BUILD @@ -154,27 +154,6 @@ java_test( ], ) -java_test( - name = "GcpHubClientTest", - size = "medium", - srcs = [ - "GcpHubClientTest.java", - ], - deps = [ - "//src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java:gcp_environment", - "//src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java:gcp_hub_client", - "//src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java:gcp_metadata", - "//src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java:hub_client", - "//src/agent/internals/src/main/java/com/google/devtools/cdbg/debuglets/java:mapper", - "@maven//:com_google_auth_google_auth_library_oauth2_http", - "@maven//:com_google_code_gson_gson", - "@maven//:com_google_guava_guava", - "@maven//:com_google_truth_truth", - "@maven//:junit_junit", - "@maven//:org_mockito_mockito_core", - ], -) - java_test( name = "YamlConfigParserTest", size = "small", diff --git a/src/agent/internals/src/test/java/com/google/devtools/cdbg/debuglets/java/GcpHubClientTest.java b/src/agent/internals/src/test/java/com/google/devtools/cdbg/debuglets/java/GcpHubClientTest.java deleted file mode 100644 index 3e0d29a8..00000000 --- a/src/agent/internals/src/test/java/com/google/devtools/cdbg/debuglets/java/GcpHubClientTest.java +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * 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 com.google.devtools.cdbg.debuglets.java; - -import static com.google.common.truth.Truth.assertThat; -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.auth.oauth2.GoogleCredentials; -import com.google.common.collect.ImmutableMap; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLStreamHandler; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -/** Unit test for {@link GcpHubClient}. */ -@RunWith(JUnit4.class) -public class GcpHubClientTest { - static interface MockServer { - HttpURLConnection openConnection(String path); - } - - private static final ImmutableMap DEFAULT_LABELS = - ImmutableMap.builder() - .put("module", "default") - .put("version", "v1") - .put("minorversion", "12345") - .buildOrThrow(); - - private static final String EXTERNAL_REGISTER_DEBUGGEE_MESSAGE = - "{\"debuggee\":{" - + "\"project\":\"123456789\"," - + "\"uniquifier\":\"we-are-not-going-to-compute-that\"," - + "\"description\":\"someone-else-will-generate-this-file-for-us\"," - + "\"agentVersion\":\"google.com/unit-test/@123456\"," - + "\"sourceContexts\":[]," - + "\"canaryMode\":\"CANARY_MODE_DEFAULT_ENABLED\"" - + "}}"; - - /** Useful empty extra debuggee labels map to use for registerDebuggee calls. */ - private static final ImmutableMap EMPTY_EXTRA_DEBUGGEE_LABELS = - ImmutableMap.of(); - - @Rule public TemporaryFolder folder1 = new TemporaryFolder(); - @Rule public TemporaryFolder folder2 = new TemporaryFolder(); - @Rule public TemporaryFolder folder3 = new TemporaryFolder(); - @Rule public TemporaryFolder folder4 = new TemporaryFolder(); - @Rule public TemporaryFolder folder5 = new TemporaryFolder(); - @Rule public final MockitoRule mocks = MockitoJUnit.rule(); - - @Mock private MockServer mockServer; - - private MetadataQuery metadata; - - private URL baseUrl; - - private ClassPathLookup classPathLookup = new ClassPathLookup(false, null, ""); - - /** Body of last RegisterDebuggee request. */ - private String registerDebuggeeRequest; - - @Before - public void setUp() throws MalformedURLException { - baseUrl = - new URL( - "mock", - "debuglet.controller", - 80, - "/", - new URLStreamHandler() { - @Override - protected URLConnection openConnection(URL url) throws IOException { - String base = "mock://debuglet.controller:80/"; - assertThat(url.toString()).startsWith(base); - - return Objects.requireNonNull( - mockServer.openConnection(url.toString().substring(base.length()))); - } - }); - - metadata = - new MetadataQuery() { - @Override - public String getProjectNumber() { - return "123456789"; - } - - @Override - public GoogleCredentials getGoogleCredential() { - return null; // Not needed for GcpHubClient - } - - @Override - public String getProjectId() { - return "mock-project-id"; - } - - @Override - public String getAccessToken() { - return "ya29"; - } - - @Override - public void shutdown() {} - }; - } - - @Test - public void registerDebuggeeSuccess() throws Exception { - registerDebuggee(); - assertThat(registerDebuggeeRequest) - .matches( - "\\{\"debuggee\":\\{" - + "\"project\":\"123456789\"," - + "\"uniquifier\":\"[0-9A-F]+\"," - + "\"description\":\"mock-project-id-default-v1-12345\"," - + "\"labels\":\\{" - + "\"minorversion\":\"12345\"," - + "\"module\":\"default\"," - + "\"version\":\"v1\"\\}," - + "\"agentVersion\":" - + "\"google.com/java-gcp/@[0-9]+\"," - + "\"sourceContexts\":\\[\\]," - + "\"canaryMode\":\"CANARY_MODE_UNSPECIFIED\"" - + "\\}\\}"); - } - - @Test - public void registerDebuggeeWithExtraLabels() throws Exception { - // Ensure the extra labels provided in the register call coexist with the base labels provided - // in the constructor. - ImmutableMap extraLabels = - ImmutableMap.of("afoo", "abar", "mkfoo", "mkbar", "sfoo", "sbar"); - - registerDebuggee(extraLabels); - - assertThat(registerDebuggeeRequest) - .matches( - "\\{\"debuggee\":\\{" - + "\"project\":\"123456789\"," - + "\"uniquifier\":\"[0-9A-F]+\"," - + "\"description\":\"mock-project-id-default-v1-12345\"," - + "\"labels\":\\{" - + "\"afoo\":\"abar\"," - + "\"minorversion\":\"12345\"," - + "\"mkfoo\":\"mkbar\"," - + "\"module\":\"default\"," - + "\"sfoo\":\"sbar\"," - + "\"version\":\"v1\"\\}," - + "\"agentVersion\":" - + "\"google.com/java-gcp/@[0-9]+\"," - + "\"sourceContexts\":\\[\\]," - + "\"canaryMode\":\"CANARY_MODE_UNSPECIFIED\"" - + "\\}\\}"); - } - - @Test - public void registerDebuggeeFromFile() throws Exception { - File file = folder1.newFile("register-debuggee-message.json"); - writeContent(file, EXTERNAL_REGISTER_DEBUGGEE_MESSAGE); - - try { - System.setProperty("com.google.cdbg.debuggee.file", file.toString()); - registerDebuggee(); - assertThat(registerDebuggeeRequest).isEqualTo(EXTERNAL_REGISTER_DEBUGGEE_MESSAGE); - } finally { - System.clearProperty("com.google.cdbg.debuggee.file"); - } - } - - @Test - public void registerDebuggeeFromString() throws Exception { - try { - System.setProperty("com.google.cdbg.debuggee.json", EXTERNAL_REGISTER_DEBUGGEE_MESSAGE); - registerDebuggee(); - assertThat(registerDebuggeeRequest).isEqualTo(EXTERNAL_REGISTER_DEBUGGEE_MESSAGE); - } finally { - System.clearProperty("com.google.cdbg.debuggee.json"); - } - } - - @Test - public void registerDebuggeeDisabled() throws Exception { - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(new ByteArrayOutputStream()); - when(connection.getInputStream()) - .thenReturn(streamFromString("{\"debuggee\":{\"id\":\"A\",\"isDisabled\":true}}")); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - assertThat(new GcpHubClient(baseUrl, metadata, classPathLookup, DEFAULT_LABELS) - .registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS)) - .isFalse(); - } - - @Test(expected = IOException.class) - public void registerDebuggeeFailure() throws Exception { - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getInputStream()).thenThrow(new IOException()); - when(connection.getOutputStream()).thenReturn(new ByteArrayOutputStream()); - when(connection.getErrorStream()).thenReturn(new ByteArrayInputStream("error".getBytes(UTF_8))); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - new GcpHubClient(baseUrl, metadata, classPathLookup, DEFAULT_LABELS) - .registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS); - } - - @Test - public void registerDebuggeeDescription() throws Exception { - // Map labels to expected debuggee description. - Map, String> testCases = - ImmutableMap., String>builder() - .put(ImmutableMap.of(), "mock-project-id") - .put( - ImmutableMap.of( - GcpEnvironment.DEBUGGEE_DESCRIPTION_SUFFIX_LABEL, "-suffix"), - "mock-project-id-suffix") - .put(ImmutableMap.of("module", "mymodule"), "mock-project-id-mymodule") - .put(ImmutableMap.of("version", "v1"), "mock-project-id-v1") - .put( - ImmutableMap.builder() - .put("module", "mymodule") - .put("version", "v1") - .buildOrThrow(), - "mock-project-id-mymodule-v1") - .put( - ImmutableMap.builder() - .put("module", "mymodule") - .put("version", "v1") - .put("minorversion", "37849523874") - .buildOrThrow(), - "mock-project-id-mymodule-v1-37849523874") - .buildOrThrow(); - - for (Entry, String> testCase : testCases.entrySet()) { - ByteArrayOutputStream requestStream = new ByteArrayOutputStream(); - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(requestStream); - when(connection.getInputStream()) - .thenReturn(streamFromString("{\"debuggee\":{\"id\":\"whatever\"}}")); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - assertThat(new GcpHubClient(baseUrl, metadata, classPathLookup, testCase.getKey()) - .registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS)) - .isTrue(); - - JsonElement request = JsonParser.parseString(new String(requestStream.toByteArray(), UTF_8)); - assertThat( - request - .getAsJsonObject() - .get("debuggee") - .getAsJsonObject() - .get("description") - .getAsJsonPrimitive() - .getAsString()) - .isEqualTo(testCase.getValue()); - } - } - - @Test - public void registerDebuggeeWithSourceContext() throws Exception { - // These source context files are directly on the class path. - writeContent(folder1.newFile("source-context.json"), "{\"whatIsThis\":\"value1\"}"); - writeContent(folder2.newFile("source-context.json"), "{\"whatIsThis\":\"value2\"}"); - - // This source context file has the same contents as another file, and should be discarded. - writeContent(folder3.newFile("source-context.json"), "{\"whatIsThis\":\"value2\"}"); - - // This source context file is not in the class path, but in a recognized directory relative to - // the class path. - folder4.newFolder("WEB-INF"); - folder4.newFolder("WEB-INF/classes"); - writeContent( - folder4.newFile("WEB-INF/classes/source-context.json"), "{\"whatIsThis\":\"value3\"}"); - - // This source context file is at the root directory of a foo.jar file which is on the class - // path. - File fooJar = folder5.newFile("foo.jar"); - writeContentToZipFile(fooJar, "source-context.json", "{\"whatIsThis\":\"value4\"}"); - - // This source context file is at a recognized directory inside the bar.jar file which is on the - // class path. - File barJar = folder5.newFile("bar.jar"); - writeContentToZipFile( - barJar, "WEB-INF/classes/source-context.json", "{\"whatIsThis\":\"value5\"}"); - - classPathLookup = - new ClassPathLookup( - false, - new String[] { - folder1.getRoot().toString(), - folder2.getRoot().toString(), - folder3.getRoot().toString(), - folder4.getRoot().toString(), - folder5.getRoot().toString(), - fooJar.toString(), - barJar.toString() - }, - /* agentDir= */ ""); - - ByteArrayOutputStream requestStream = new ByteArrayOutputStream(); - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(requestStream); - when(connection.getInputStream()) - .thenReturn(streamFromString("{\"debuggee\":{\"id\":\"whatever\"}}")); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - assertThat(new GcpHubClient(baseUrl, metadata, classPathLookup, DEFAULT_LABELS) - .registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS)) - .isTrue(); - - JsonElement request = JsonParser.parseString(new String(requestStream.toByteArray(), UTF_8)); - assertThat( - request - .getAsJsonObject() - .get("debuggee") - .getAsJsonObject() - .get("sourceContexts") - .toString()) - .isEqualTo( - "[" - + "{\"whatIsThis\":\"value1\"}," - + "{\"whatIsThis\":\"value2\"}," - + "{\"whatIsThis\":\"value3\"}," - + "{\"whatIsThis\":\"value4\"}," - + "{\"whatIsThis\":\"value5\"}" - + "]"); - } - - @Test(expected = Exception.class) - public void registerDebuggeeResponseNotJson() throws Exception { - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(new ByteArrayOutputStream()); - when(connection.getInputStream()).thenReturn(streamFromString("this is not a JSON")); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - new GcpHubClient(baseUrl, metadata, classPathLookup, DEFAULT_LABELS) - .registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS); - } - - @Test(expected = Exception.class) - public void registerDebuggeeResponseNotObject() throws Exception { - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(new ByteArrayOutputStream()); - when(connection.getInputStream()).thenReturn(streamFromString("[]")); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - new GcpHubClient(baseUrl, metadata, classPathLookup, DEFAULT_LABELS) - .registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS); - } - - @Test(expected = Exception.class) - public void registerDebuggeeEmptyDebuggeeId() throws Exception { - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(new ByteArrayOutputStream()); - when(connection.getInputStream()).thenReturn(streamFromString("{\"debuggee\":{\"id\":\"\"}}")); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - new GcpHubClient(baseUrl, metadata, classPathLookup, DEFAULT_LABELS) - .registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS); - } - - @Test - public void registerDebuggeeMutableDebuggeeId() throws Exception { - GcpHubClient hubClient = registerDebuggee(); - - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(new ByteArrayOutputStream()); - when(connection.getInputStream()) - .thenReturn(streamFromString("{\"debuggee\":{\"id\":\"different-id\"}}")); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - assertThat(hubClient.registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS)).isTrue(); - assertThat(hubClient.getDebuggeeId()).isEqualTo("different-id"); - } - - @Test - public void registerDebuggeeCanaryModePerperties() throws Exception { - // Verify that setting the canary mode properties correctly would change the default value of - // canaryMode. Note that the different combinations of the properties would be verified in the - // corresponding unit test. - try { - System.setProperty("com.google.cdbg.breakpoints.enable_canary", "true"); - System.setProperty("com.google.cdbg.breakpoints.allow_canary_override", "true"); - registerDebuggee(); - assertThat(registerDebuggeeRequest) - .matches(".*\"canaryMode\":\"CANARY_MODE_DEFAULT_ENABLED\".*"); - } finally { - System.clearProperty("com.google.cdbg.breakpoints.enable_canary"); - System.clearProperty("com.google.cdbg.breakpoints.allow_canary_override"); - } - } - - @Test - public void listActiveBreakpointsSuccess() throws Exception { - HubClient hubClient = registerDebuggee(); - HubClient.ListActiveBreakpointsResult result; - - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getInputStream()).thenReturn(streamFromString("{\"nextWaitToken\":\"ABC\"}")); - when(mockServer.openConnection( - "debuggees/test-debuggee-id/breakpoints" - + "?successOnTimeout=true&waitToken=init&agentId=test-agent-id")) - .thenReturn(connection); - - result = hubClient.listActiveBreakpoints(); - assertThat(result.getIsTimeout()).isFalse(); - assertThat(result.getFormat()).isEqualTo("json"); - assertThat(result.getActiveBreakpoints()).isEmpty(); - - when(connection.getInputStream()) - .thenReturn( - streamFromString( - "{\"breakpoints\":[{\"id\":\"A\"},{\"id\":\"B\"}],\"nextWaitToken\":\"DEF\"}")); - when(mockServer.openConnection( - "debuggees/test-debuggee-id/breakpoints" - + "?successOnTimeout=true&waitToken=ABC&agentId=test-agent-id")) - .thenReturn(connection); - - result = hubClient.listActiveBreakpoints(); - assertThat(result.getIsTimeout()).isFalse(); - - byte[][] breakpoints = result.getActiveBreakpoints(); - assertThat(breakpoints).hasLength(2); - - assertThat(JsonParser.parseString(new String(breakpoints[0], UTF_8)).toString()) - .isEqualTo("{\"id\":\"A\"}"); - assertThat(JsonParser.parseString(new String(breakpoints[1], UTF_8)).toString()) - .isEqualTo("{\"id\":\"B\"}"); - } - - @Test - public void listActiveBreakpointsWaitExpired() throws Exception { - HubClient hubClient = registerDebuggee(); - - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getInputStream()).thenReturn(streamFromString("{\"waitExpired\":\"true\"}")); - when(mockServer.openConnection( - "debuggees/test-debuggee-id/breakpoints" - + "?successOnTimeout=true&waitToken=init&agentId=test-agent-id")) - .thenReturn(connection); - - HubClient.ListActiveBreakpointsResult result = hubClient.listActiveBreakpoints(); - assertThat(result.getIsTimeout()).isTrue(); - } - - @Test(expected = IOException.class) - public void listActiveBreakpointsFailure() throws Exception { - HubClient hubClient = registerDebuggee(); - - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getInputStream()).thenThrow(new IOException()); - when(connection.getErrorStream()).thenReturn(new ByteArrayInputStream("error".getBytes(UTF_8))); - when(connection.getResponseCode()).thenReturn(408); - - when(mockServer.openConnection( - "debuggees/test-debuggee-id/breakpoints" - + "?successOnTimeout=true&waitToken=init&agentId=test-agent-id")) - .thenReturn(connection); - - hubClient.listActiveBreakpoints(); - } - - @Test(expected = JsonSyntaxException.class) - public void listActiveBreakpointsBadResponse() throws Exception { - HubClient hubClient = registerDebuggee(); - - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getInputStream()).thenReturn(streamFromString("not a valid json")); - - when(mockServer.openConnection( - "debuggees/test-debuggee-id/breakpoints" - + "?successOnTimeout=true&waitToken=init&agentId=test-agent-id")) - .thenReturn(connection); - - hubClient.listActiveBreakpoints(); - } - - @Test - public void transmitBreakpointSuccess() throws Exception { - HubClient hubClient = registerDebuggee(); - - ByteArrayOutputStream requestStream = new ByteArrayOutputStream(); - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(requestStream); - when(connection.getInputStream()).thenReturn(streamFromString("")); - - when(mockServer.openConnection("debuggees/test-debuggee-id/breakpoints/bpid")) - .thenReturn(connection); - - hubClient.transmitBreakpointUpdate( - "json", "bpid", "{\"whatIsThis\":\"breakpoint\"}".getBytes(UTF_8)); - - JsonElement request = JsonParser.parseString(new String(requestStream.toByteArray(), UTF_8)); - assertThat(request.toString()).isEqualTo("{\"breakpoint\":{\"whatIsThis\":\"breakpoint\"}}"); - } - - @Test(expected = UnsupportedOperationException.class) - public void transmitBreakpointUpdateBadFormat() throws Exception { - HubClient hubClient = registerDebuggee(); - hubClient.transmitBreakpointUpdate("protobuf", "bpid", new byte[0]); - } - - @Test - public void transmitBreakpointTransientError() throws Exception { - for (int statusCode : new int[] {408, 500}) { - HubClient hubClient = registerDebuggee(); - - ByteArrayOutputStream requestStream = new ByteArrayOutputStream(); - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(requestStream); - when(connection.getInputStream()).thenThrow(new IOException()); - when(connection.getErrorStream()).thenReturn(new ByteArrayInputStream("err".getBytes(UTF_8))); - when(connection.getResponseCode()).thenReturn(statusCode); - - when(mockServer.openConnection("debuggees/test-debuggee-id/breakpoints/bpid")) - .thenReturn(connection); - - IOException transmitException = null; - try { - hubClient.transmitBreakpointUpdate( - "json", "bpid", "{\"whatIsThis\":\"breakpoint\"}".getBytes(UTF_8)); - } catch (IOException e) { - transmitException = e; - } - - assertThat(transmitException).isNotNull(); - } - } - - @Test - public void transmitBreakpointPermanentError() throws Exception { - for (int statusCode : new int[] {400, 403, 404}) { - HubClient hubClient = registerDebuggee(); - - ByteArrayOutputStream requestStream = new ByteArrayOutputStream(); - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(requestStream); - when(connection.getInputStream()).thenThrow(new IOException()); - when(connection.getResponseCode()).thenReturn(statusCode); - when(connection.getResponseMessage()).thenReturn("something failed"); - when(connection.getErrorStream()).thenReturn(new ByteArrayInputStream("err".getBytes(UTF_8))); - - when(mockServer.openConnection("debuggees/test-debuggee-id/breakpoints/bpid")) - .thenReturn(connection); - - hubClient.transmitBreakpointUpdate( - "json", "bpid", "{\"whatIsThis\":\"breakpoint\"}".getBytes(UTF_8)); - } - } - - /** Common code to get the debuggee registered for all test cases requiring that. */ - private GcpHubClient registerDebuggee() throws Exception { - return registerDebuggee(EMPTY_EXTRA_DEBUGGEE_LABELS); - } - - /** - * Common code to get the debuggee registered with extra labels provided in the registerDebuggee - * call. - */ - private GcpHubClient registerDebuggee(Map extraLabels) - throws Exception { - ByteArrayOutputStream registerDebuggeeBodyStream = new ByteArrayOutputStream(); - HttpURLConnection connection = mock(HttpURLConnection.class); - when(connection.getOutputStream()).thenReturn(registerDebuggeeBodyStream); - when(connection.getInputStream()) - .thenReturn( - streamFromString( - "{\"debuggee\":{\"id\":\"test-debuggee-id\",\"idDisabled\":false}," - + "\"agentId\":\"test-agent-id\"}")); - - when(mockServer.openConnection("debuggees/register")).thenReturn(connection); - - GcpHubClient hubClient = new GcpHubClient(baseUrl, metadata, classPathLookup, DEFAULT_LABELS); - assertThat(hubClient.registerDebuggee(extraLabels)).isTrue(); - assertThat(hubClient.getDebuggeeId()).isEqualTo("test-debuggee-id"); - assertThat(hubClient.getAgentId()).isEqualTo("test-agent-id"); - - registerDebuggeeRequest = registerDebuggeeBodyStream.toString(UTF_8.name()); - - return hubClient; - } - - private void writeContent(File file, String content) - throws FileNotFoundException, UnsupportedEncodingException { - try (PrintWriter writer = new PrintWriter(file, "UTF-8")) { - writer.write(content); - } - } - - /** - * Creates a zip file with a single file inside it. - * - * @param file a file whose contents will be populated as a zip file - * @param filePath the path of the file that will be put inside the zip file - * @param content the data that will be put into the inner file - */ - private void writeContentToZipFile(File file, String filePath, String content) - throws IOException { - ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file)); - - // First, add all directories in the file path to the zip file. - // E.g., for filePath=a/b/c add: "a", "a/b". - int index = filePath.indexOf('/'); - while (index != -1) { - out.putNextEntry(new ZipEntry(filePath.substring(0, index))); - index = filePath.indexOf('/', index + 1); - } - - // Then add the file "a/b/c" to the zip file. - out.putNextEntry(new ZipEntry(filePath)); - - // Write the contents of the file. - out.write(content.getBytes(UTF_8)); - out.close(); - } - - private ByteArrayInputStream streamFromString(String s) { - return new ByteArrayInputStream(s.getBytes(UTF_8)); - } -} diff --git a/src/agent/jvmti_globals.cc b/src/agent/jvmti_globals.cc index 895c01ac..0b913f45 100644 --- a/src/agent/jvmti_globals.cc +++ b/src/agent/jvmti_globals.cc @@ -45,7 +45,6 @@ #include "jni_proxy_api_client_datetime.h" #include "jni_proxy_firebaseclient.h" #include "jni_proxy_gcpbreakpointlabelsprovider.h" -#include "jni_proxy_gcphubclient.h" #include "jni_proxy_yamlconfigparser.h" #include "jni_bridge.h" #include "model_json.h" @@ -78,9 +77,10 @@ ABSL_FLAG(string, service_account_email, "", ABSL_FLAG(string, service_account_json_file, "", "Path to JSON file containing private key of the service account"); -ABSL_FLAG(bool, use_firebase, false, - "Enables the use of a Firebase RTDB backend instead of the Google " - "Cloud Debugger backend."); +ABSL_FLAG(bool, use_firebase, true, + "This flag no longer has any effect as the Firebase RTDB is the only " + "supported backand, It is being kept for backwards compatibility to " + "prevent loading failure in cases it is set."); ABSL_FLAG(string, firebase_db_url, "", @@ -356,11 +356,8 @@ Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { std::unique_ptr bridge( new devtools::cdbg::JniBridge( [] () { - return ( - absl::GetFlag(FLAGS_use_firebase) ? - jniproxy::FirebaseClient()->NewObject() : - jniproxy::GcpHubClient()->NewObject() - ).Release(devtools::cdbg::ExceptionAction::LOG_AND_IGNORE); + return jniproxy::FirebaseClient()->NewObject() + .Release(devtools::cdbg::ExceptionAction::LOG_AND_IGNORE); }, devtools::cdbg::BreakpointToJson, devtools::cdbg::BreakpointFromJson)); @@ -387,7 +384,6 @@ Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { jniproxy::BindDateTimeWithClassLoader, jniproxy::BindGcpBreakpointLabelsProviderWithClassLoader, jniproxy::BindFirebaseClientWithClassLoader, - jniproxy::BindGcpHubClientWithClassLoader, jniproxy::BindYamlConfigParserWithClassLoader, }, std::move(bridge), diff --git a/src/codegen/BUILD b/src/codegen/BUILD index c93823d7..865e126b 100644 --- a/src/codegen/BUILD +++ b/src/codegen/BUILD @@ -18,7 +18,6 @@ ALL_GENERATED_CLASSES = [ "firebaseclient", "gcpbreakpointlabelsprovider", "gcpdebugletversion", - "gcphubclient", "hubclient", "hubclient_listactivebreakpointsresult", "iterable", diff --git a/src/codegen/config.json b/src/codegen/config.json index 26c2b137..bd6b16ac 100644 --- a/src/codegen/config.json +++ b/src/codegen/config.json @@ -283,15 +283,6 @@ } ], "nativeNamespace": "jniproxy" - }, - { - "className": "com.google.devtools.cdbg.debuglets.java.GcpHubClient", - "methods": [ - { - "methodName": "" - } - ], - "nativeNamespace": "jniproxy" }, { "className": "com.google.devtools.cdbg.debuglets.java.YamlConfigParser",