From 4dcb4131a42c334054bc20c483d7c209bbb5ce2d Mon Sep 17 00:00:00 2001 From: Elyes Cherfa Date: Tue, 10 Dec 2024 17:32:28 +0100 Subject: [PATCH] Issue #424: Add CLI options for specific query execution - HTTP * Refactored HttpCli to exclude port, hostname, path & protocol. These will be extracted from the Url. * Made the neccessary changes to make everything work. * Added unit tests. * Tested the CLI. --- .../metricshub/cli/http/HttpCli.java | 184 +++++++++++++----- .../cli/service/MetricsHubCliService.java | 2 +- .../metricshub/cli/http/HttpCliTest.java | 149 +++++++------- .../extension/http/HttpExtension.java | 44 +++-- .../extension/http/HttpExtensionTest.java | 13 +- 5 files changed, 249 insertions(+), 143 deletions(-) diff --git a/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/cli/http/HttpCli.java b/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/cli/http/HttpCli.java index d87e1745d..55b3b9129 100644 --- a/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/cli/http/HttpCli.java +++ b/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/cli/http/HttpCli.java @@ -22,6 +22,8 @@ */ import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.BooleanNode; +import com.fasterxml.jackson.databind.node.IntNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; @@ -33,30 +35,29 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; - import lombok.Data; import org.fusesource.jansi.AnsiConsole; import org.sentrysoftware.metricshub.cli.service.CliExtensionManager; +import org.sentrysoftware.metricshub.cli.service.ConsoleService; +import org.sentrysoftware.metricshub.cli.service.MetricsHubCliService.CliPasswordReader; import org.sentrysoftware.metricshub.cli.service.PrintExceptionMessageHandlerService; -import org.sentrysoftware.metricshub.cli.service.protocol.HttpConfigCli; import org.sentrysoftware.metricshub.engine.common.IQuery; import org.sentrysoftware.metricshub.engine.configuration.IConfiguration; -import org.sentrysoftware.metricshub.engine.connector.model.common.ResultContent; import picocli.CommandLine; -import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; import picocli.CommandLine.Model.CommandSpec; import picocli.CommandLine.Option; import picocli.CommandLine.ParameterException; -import picocli.CommandLine.Parameters; import picocli.CommandLine.Spec; @Data @Command(name = "httpcli", description = "HTTP client for testing purposes.") public class HttpCli implements IQuery, Callable { - @Parameters(index = "0", paramLabel = "HOSTNAME", description = "Hostname or IP address of the host to monitor") - String hostname; + public static final String HTTP = "http"; + public static final String HTTPS = "https"; + public static final int DEFAULT_HTTP_PORT = 80; + public static final int DEFAULT_HTTPS_PORT = 443; @Spec CommandSpec spec; @@ -66,7 +67,7 @@ public class HttpCli implements IQuery, Callable { @Option( names = "--http-method", - order = 3, + order = 2, paramLabel = "METHOD", description = "HTTP request type (GET|POST|PUT|DELETE)" ) @@ -74,7 +75,7 @@ public class HttpCli implements IQuery, Callable { @Option( names = "--http-header", - order = 4, + order = 3, paramLabel = "HEADER", split = ",", description = "Headers to be added to the HTTP request." @@ -83,18 +84,18 @@ public class HttpCli implements IQuery, Callable { @Option( names = "--http-header-file", - order = 5, + order = 4, paramLabel = "HEADERFILE", description = "Path of the file containing header to be added to the HTTP request." ) private String headerFile; - @Option(names = "--http-body", order = 6, paramLabel = "BODY", description = "Body of the HTTP request.") + @Option(names = "--http-body", order = 5, paramLabel = "BODY", description = "Body of the HTTP request.") private String body; @Option( names = "--http-body-file", - order = 7, + order = 6, paramLabel = "BODYFILE", description = "Path of the file containing the HTTP request body." ) @@ -102,14 +103,38 @@ public class HttpCli implements IQuery, Callable { @Option( names = "--http-authentication-token", - order = 8, + order = 7, paramLabel = "TOKEN", description = " The authentication token for the HTTP request." ) private String authenticationToken; - @ArgGroup(exclusive = false, heading = "%n@|bold,underline HTTP Options|@:%n") - HttpConfigCli httpConfigCli; + @Option( + names = { "--http-username" }, + order = 8, + paramLabel = "USER", + description = "Username for HTTP authentication" + ) + private String username; + + @Option( + names = { "--http-password" }, + order = 9, + paramLabel = "P4SSW0RD", + description = "Password for the HTTP protocol", + arity = "0..1", + interactive = true + ) + private char[] password; + + @Option( + names = "--http-timeout", + order = 10, + paramLabel = "TIMEOUT", + defaultValue = "120", + description = "Timeout in seconds for HTTP operations (default: ${DEFAULT-VALUE} s)" + ) + private String timeout; @Option(names = { "-h", "-?", "--help" }, usageHelp = true, description = "Shows this help message and exits") boolean usageHelpRequested; @@ -117,19 +142,17 @@ public class HttpCli implements IQuery, Callable { @Option(names = "-v", order = 7, description = "Verbose mode (repeat the option to increase verbosity)") boolean[] verbose; + java.net.URL parsedUrl; + static Set httpMethods = Set.of("GET", "POST", "PUT", "DELETE"); @Override public JsonNode getQuery() { final ObjectNode queryNode = JsonNodeFactory.instance.objectNode(); - if (method != null) { - queryNode.set("method", new TextNode(method.toUpperCase())); - } + queryNode.set("method", new TextNode(method != null ? method.toUpperCase() : "GET")); - if (url != null) { - queryNode.set("url", new TextNode(url)); - } + queryNode.set("url", new TextNode(url)); try { final String headerContent = getHeaderContent(); @@ -137,7 +160,7 @@ public JsonNode getQuery() { queryNode.set("header", new TextNode(headerContent)); } } catch (IOException e) { - + throw new IllegalStateException("Could not read the header.", e); } try { @@ -146,7 +169,7 @@ public JsonNode getQuery() { queryNode.set("body", new TextNode(bodyContent)); } } catch (IOException e) { - + throw new IllegalStateException("Could not read the body.", e); } queryNode.set("resultContent", new TextNode("all")); @@ -160,18 +183,19 @@ public JsonNode getQuery() { /** * Retrieves the body content for the HTTP request. - * If the body is specified directly, it is returned. + * If the body is specified directly, it is returned. * If a body file is specified, its contents are read and returned. - * - * @param printWriter the PrintWriter to log any errors during file reading + * * @return the body content as a string, or null if neither body nor body file is set. * @throws IOException if an error occurs while reading the bodyFile. */ - public String getBodyContent() throws IOException{ + public String getBodyContent() throws IOException { if (body != null) { return body; - } else { + } else if (bodyFile != null) { return Files.readString(Path.of(bodyFile), StandardCharsets.UTF_8); + } else { + return null; } } @@ -179,8 +203,7 @@ public String getBodyContent() throws IOException{ * Retrieves the header content for the HTTP request. * If headers are specified directly, they are formatted and returned. * If a header file is specified, its contents are read and returned. - * - * @param printWriter the PrintWriter to log any errors during file reading + * * @return the header content as a string, or null if neither headers nor a header file is set. * @throws IOException if an error occurs while reading the headerFile. */ @@ -190,37 +213,48 @@ public String getHeaderContent() throws IOException { if (headers != null) { headers.forEach((key, value) -> header.append(String.format("%s: %s%n", key, value))); return header.toString(); - } else { + } else if (headerFile != null) { header.append(Files.readString(Path.of(headerFile), StandardCharsets.UTF_8)); return header.toString(); + } else { + return null; + } + } + + /** + * Try to start the interactive mode to request and set HTTP password + * + * @param passwordReader password reader which displays the prompt text and wait for user's input + */ + void tryInteractivePassword(final CliPasswordReader passwordReader) { + if (username != null && password == null) { + password = (passwordReader.read("%s password for HTTP: ", username)); } } /** * Validates the HTTP request configuration and parameters. * Ensures required fields are set and checks for conflicts in headers and body configuration. - * + * * @throws ParameterException if validation fails due to missing or conflicting parameters. */ void validate() throws ParameterException { - // Validating HTTP configuration - if (httpConfigCli == null) { - throw new ParameterException(spec.commandLine(), "HTTP/HTTPS protocol must be configured: --http, --https."); + // Can we ask for passwords interactively? + final boolean interactive = ConsoleService.hasConsole(); + + // Password + if (interactive) { + tryInteractivePassword(System.console()::readPassword); } + // Validating HTTP Url + validateUrl(); + // Validating HTTP methods if (method != null && !httpMethods.contains(method.toUpperCase())) { throw new ParameterException(spec.commandLine(), String.format("Unknown HTTP request method: %s.", method)); } - // Validating URL & Path - if (url == null && path == null) { - throw new ParameterException( - spec.commandLine(), - "At least one of the parameters must be specified: --http-url or --http-path." - ); - } - // Validating headers if (headers != null && headerFile != null) { throw new ParameterException( @@ -254,8 +288,51 @@ void validate() throws ParameterException { ); } } + } + + /** + * Validates the URL's syntax using Java's URL and URI classes. + * + * @throws ParameterException if the URL is invalid + */ + void validateUrl() { + try { + // Performing a basic validation of the URL format + parsedUrl = new java.net.URL(url); + // Enforces stricter compliance, catching invalid characters. + parsedUrl.toURI(); + } catch (Exception e) { + throw new ParameterException(spec.commandLine(), "Invalid URL: " + e.getMessage(), e); + } + } + + /** + * Resolves the port number from the URL or returns a default value. + * + * @return the resolved or default port number + * @throws ParameterException if the URL is invalid + */ + int resolvePortFromUrl() { + try { + // Check if the port is explicitly specified + int port = parsedUrl.getPort(); + if (port != -1) { + return port; // Port found in the URL + } + + // Determine the default port based on protocol + String protocol = parsedUrl.getProtocol(); + if (HTTP.equalsIgnoreCase(protocol)) { + return DEFAULT_HTTP_PORT; + } else if (HTTPS.equalsIgnoreCase(protocol)) { + return DEFAULT_HTTPS_PORT; + } + } catch (Exception e) { + throw new ParameterException(spec.commandLine(), "Invalid URL: " + e.getMessage(), e); + } - ResultContent.detect(resultContent); + // Default to 443 if no protocol or port is found + return DEFAULT_HTTPS_PORT; } /** @@ -300,11 +377,24 @@ public Integer call() throws Exception { validate(); CliExtensionManager .getExtensionManagerSingleton() - .findExtensionByType("http") + .findExtensionByType(HTTP) .ifPresent(extension -> { try { - IConfiguration protocol = httpConfigCli.toProtocol(null, null); - protocol.setHostname(hostname); + final ObjectNode configuration = JsonNodeFactory.instance.objectNode(); + + configuration.set(HTTPS, BooleanNode.valueOf(parsedUrl.getProtocol().equals(HTTPS))); + + configuration.set("username", new TextNode(username)); + + if (password != null) { + configuration.set("password", new TextNode(String.valueOf(password))); + } + + configuration.set("port", new IntNode(resolvePortFromUrl())); + configuration.set("timeout", new TextNode(timeout)); + + IConfiguration protocol = extension.buildConfiguration(HTTP, configuration, null); + protocol.setHostname(parsedUrl.getHost()); extension.executeQuery(protocol, getQuery(), printWriter); } catch (Exception e) { printWriter.print("HTTP - Invalid configuration detected.\n"); diff --git a/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/cli/service/MetricsHubCliService.java b/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/cli/service/MetricsHubCliService.java index ce0c5b7ee..b56db1def 100644 --- a/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/cli/service/MetricsHubCliService.java +++ b/metricshub-agent/src/main/java/org/sentrysoftware/metricshub/cli/service/MetricsHubCliService.java @@ -776,7 +776,7 @@ int listAllConnectors(final ConnectorStore connectorStore, final PrintWriter pri } @FunctionalInterface - interface CliPasswordReader { + public interface CliPasswordReader { /** * Applies this function to the given arguments to read a password * diff --git a/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/cli/http/HttpCliTest.java b/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/cli/http/HttpCliTest.java index de9b2733f..06ed1230a 100644 --- a/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/cli/http/HttpCliTest.java +++ b/metricshub-agent/src/test/java/org/sentrysoftware/metricshub/cli/http/HttpCliTest.java @@ -2,17 +2,14 @@ import static org.junit.jupiter.api.Assertions.*; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; import java.io.PrintWriter; import java.io.StringWriter; +import java.net.MalformedURLException; import java.util.Map; - import org.junit.jupiter.api.Test; -import org.sentrysoftware.metricshub.cli.service.protocol.HttpConfigCli; - -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.node.TextNode; - import picocli.CommandLine; import picocli.CommandLine.ParameterException; @@ -22,63 +19,41 @@ class HttpCliTest { CommandLine commandLine; PrintWriter printWriter = new PrintWriter(new StringWriter()); - private final static String HOSTNAME = ""; - private final static String HTTP_GET = ""; - private final static String URL = ""; - private final static Map HEADERS = Map.of("Content-Type", "application/xml"); - private final static String BODY = ""; - private final static String AUTHENTICATION_TOKEN = "Q5SD7SDF2BCV8ZER4"; - private final static String RESULT_CONTENT = "all"; - private final static String FILE_HEADER = - "Content-Type: application/xml\r\n" - + "User-Agent: Mozilla/5.0\r\n" - + "Accept: text/html\r\n" - + "Accept-Language: en-US\r\n" - + "Cache-Control: no-cache"; + private static final String HTTP_GET = "GET"; + private static final String WRONG_HTTP_METHOD = "WrongMethod"; + private static final String URL = "https://hostname:443/www.test.com"; + private static final String WRONG_URL = "WrongUrl"; + private static final String WRONG_URL_WITH_SPACE = "https://hostname:443/www.test.com/path 1/"; + private static final String WRONG_HEADER_FILE_PATH = "wrong/path/header.txt"; + private static final String HEADER_FILE_PATH = "src/test/resources/cli/header.txt"; + private static final Map HEADERS = Map.of("Content-Type", "application/xml"); + private static final String BODY = ""; + private static final String BODY_FILE_PATH = "src/test/resources/cli/body.txt"; + private static final String WRONG_BODY_FILE_PATH = "wrong/path/body.txt"; + private static final String AUTHENTICATION_TOKEN = "Q5SD7SDF2BCV8ZER4"; + private static final String RESULT_CONTENT = "all"; + private static final String FILE_HEADER = String.join( + "\r\n", + "Content-Type: application/xml", + "User-Agent: Mozilla/5.0", + "Accept: text/html", + "Accept-Language: en-US", + "Cache-Control: no-cache" + ); void initCli() { httpCli = new HttpCli(); commandLine = new CommandLine(httpCli); } - void initHttpCli() { - httpCli = new HttpCli(); - final CommandLine commandLine = new CommandLine(httpCli); - - commandLine.execute( - "hostname", - "--http", - "--http-username", - "username", - "--http-password", - "password", - "--http-path", - "path", - "--http-url", - "url", - "--http-header", - "key1, value1", - "--http-header", - "key2, value2", - "--http-body", - "body", - "--http-authenticationToken", - "authenticationToken", - "--http-resultContent", - "all" - ); - } - @Test void testGetQuery() { initCli(); - httpCli.setHostname(HOSTNAME); httpCli.setMethod(HTTP_GET); httpCli.setUrl(URL); httpCli.setHeaders(HEADERS); httpCli.setBody(BODY); httpCli.setAuthenticationToken(AUTHENTICATION_TOKEN); - httpCli.setResultContent(RESULT_CONTENT); StringBuilder header = new StringBuilder(); HEADERS.forEach((key, value) -> header.append(String.format("%s: %s%n", key, value))); @@ -94,75 +69,97 @@ void testGetQuery() { } @Test - void testGetHeader() throws Exception{ + void testGetHeader() throws Exception { initCli(); httpCli.setHeaders(HEADERS); assertEquals("Content-Type: application/xml\r\n", httpCli.getHeaderContent()); httpCli.setHeaders(null); - httpCli.setHeaderFile("src/test/resources/cli/header.txt"); + httpCli.setHeaderFile(HEADER_FILE_PATH); assertEquals(FILE_HEADER, httpCli.getHeaderContent()); } @Test - void testGetBody() throws Exception{ + void testGetBody() throws Exception { initCli(); httpCli.setBody(BODY); assertEquals(BODY, httpCli.getBody()); httpCli.setBody(null); - httpCli.setBodyFile("src/test/resources/cli/body.txt"); + httpCli.setBodyFile(BODY_FILE_PATH); assertEquals(BODY, httpCli.getBodyContent()); } + @Test + void testValidateUrl() { + initCli(); + httpCli.setUrl(WRONG_URL_WITH_SPACE); + ParameterException exceptionMessage = assertThrows(ParameterException.class, () -> httpCli.validateUrl()); + assertTrue(exceptionMessage.getMessage().contains("Invalid URL")); + httpCli.setUrl(URL); + assertDoesNotThrow(() -> httpCli.validateUrl()); + } + + @Test + void testResolvePortFromUrl() throws MalformedURLException { + initCli(); + httpCli.parsedUrl = new java.net.URL(URL); + assertEquals(443, httpCli.resolvePortFromUrl()); + + httpCli.parsedUrl = new java.net.URL("https://www.test.com"); + assertEquals(443, httpCli.resolvePortFromUrl()); + + httpCli.parsedUrl = new java.net.URL("http://www.test.com"); + assertEquals(80, httpCli.resolvePortFromUrl()); + + httpCli.parsedUrl = new java.net.URL("http://hostname:555/subdomain"); + assertEquals(555, httpCli.resolvePortFromUrl()); + } + @Test void testValidate() { initCli(); - // HttpConfigCli must be configured. + // URL must be valid (contains the protocol at the beginning). + httpCli.setUrl(WRONG_URL); ParameterException exceptionMessage = assertThrows(ParameterException.class, () -> httpCli.validate()); - assertEquals("HTTP/HTTPS protocol must be configured: --http, --https.", exceptionMessage.getMessage()); - httpCli.setHttpConfigCli(new HttpConfigCli()); + assertTrue(exceptionMessage.getMessage().contains("Invalid URL:")); + httpCli.setUrl(URL); // Method must be : GET/POST/PUT/DELETE or empty (default: GET) - httpCli.setMethod("WrongMethod"); + httpCli.setMethod(WRONG_HTTP_METHOD); exceptionMessage = assertThrows(ParameterException.class, () -> httpCli.validate()); assertEquals("Unknown HTTP request method: WrongMethod.", exceptionMessage.getMessage()); - httpCli.setMethod("get"); - - // At least URL or Path must be speficied - exceptionMessage = assertThrows(ParameterException.class, () -> httpCli.validate()); - assertEquals("At least one of the parameters must be specified: --http-url or --http-path.", exceptionMessage.getMessage()); - httpCli.setUrl(URL); + httpCli.setMethod(HTTP_GET); // Wrong headerFile path - httpCli.setHeaderFile("wrong/path/header.txt"); + httpCli.setHeaderFile(WRONG_HEADER_FILE_PATH); exceptionMessage = assertThrows(ParameterException.class, () -> httpCli.validate()); assertTrue(exceptionMessage.getMessage().contains("Error while reading header file")); // Only one header (headers or headerFile) must be specified. httpCli.setHeaders(HEADERS); - httpCli.setHeaderFile("src/test/resources/cli/header.txt"); + httpCli.setHeaderFile(HEADER_FILE_PATH); exceptionMessage = assertThrows(ParameterException.class, () -> httpCli.validate()); - assertEquals("Conflict - Two headers have been configured: --http-header and --http-header-file.", exceptionMessage.getMessage()); + assertEquals( + "Conflict - Two headers have been configured: --http-header and --http-header-file.", + exceptionMessage.getMessage() + ); httpCli.setHeaders(null); // Wrong bodyFile path - httpCli.setBodyFile("wrong/path/body.txt"); + httpCli.setBodyFile(WRONG_BODY_FILE_PATH); exceptionMessage = assertThrows(ParameterException.class, () -> httpCli.validate()); assertTrue(exceptionMessage.getMessage().contains("Error while reading body file")); // Only one body (body or bodyFile) must be specified. httpCli.setBody(BODY); - httpCli.setBodyFile("src/test/resources/cli/body.txt"); + httpCli.setBodyFile(BODY_FILE_PATH); exceptionMessage = assertThrows(ParameterException.class, () -> httpCli.validate()); - assertEquals("Conflict - Two bodies have been configured: --http-body and --http-body-file.", exceptionMessage.getMessage()); + assertEquals( + "Conflict - Two bodies have been configured: --http-body and --http-body-file.", + exceptionMessage.getMessage() + ); httpCli.setBody(null); - // Result Content must be : All, Body, Header, httpStatus or http_status - httpCli.setResultContent("wrongResultContent"); - IllegalArgumentException illegalExceptionMessage = assertThrows(IllegalArgumentException.class, () -> httpCli.validate()); - assertTrue(illegalExceptionMessage.getMessage().contains("is not a supported ResultContent")); - httpCli.setResultContent(RESULT_CONTENT); - assertDoesNotThrow(() -> httpCli.validate()); } } diff --git a/metricshub-http-extension/src/main/java/org/sentrysoftware/metricshub/extension/http/HttpExtension.java b/metricshub-http-extension/src/main/java/org/sentrysoftware/metricshub/extension/http/HttpExtension.java index b2f7c8710..657e6d49b 100644 --- a/metricshub-http-extension/src/main/java/org/sentrysoftware/metricshub/extension/http/HttpExtension.java +++ b/metricshub-http-extension/src/main/java/org/sentrysoftware/metricshub/extension/http/HttpExtension.java @@ -46,6 +46,8 @@ import org.sentrysoftware.metricshub.engine.strategy.detection.CriterionTestResult; import org.sentrysoftware.metricshub.engine.strategy.source.SourceTable; import org.sentrysoftware.metricshub.engine.telemetry.TelemetryManager; +import org.sentrysoftware.metricshub.extension.http.utils.Body; +import org.sentrysoftware.metricshub.extension.http.utils.Header; import org.sentrysoftware.metricshub.extension.http.utils.HttpRequest; /** @@ -218,19 +220,17 @@ public String getIdentifier() { @Override public String executeQuery(IConfiguration configuration, JsonNode query, PrintWriter printWriter) { - final String hostname = configuration.getHostname(); final String method = query.get("method").asText(); final JsonNode url = query.get("url"); - final JsonNode path = query.get("path"); final JsonNode header = query.get("header"); final JsonNode body = query.get("body"); final JsonNode resultContent = query.get("resultContent"); final JsonNode authenticationToken = query.get("authenticationToken"); final HostConfiguration hostConfiguration = HostConfiguration - .builder() - .configurations(Map.of(HttpConfiguration.class, configuration)) - .build(); + .builder() + .configurations(Map.of(HttpConfiguration.class, configuration)) + .build(); final TelemetryManager telemetryManager = TelemetryManager.builder().hostConfiguration(hostConfiguration).build(); final HttpRequest httpRequest = HttpRequest @@ -239,7 +239,6 @@ public String executeQuery(IConfiguration configuration, JsonNode query, PrintWr .httpConfiguration((HttpConfiguration) configuration) .method(method) .url(notNull(url) ? url.asText() : null) - .path(notNull(path) ? path.asText() : null) .header(notNull(header) ? header.asText() : null, Map.of(), "", hostname) .body(notNull(body) ? body.asText() : null, Map.of(), "", hostname) .resultContent(notNull(resultContent) ? ResultContent.detect(resultContent.asText()) : ResultContent.ALL) @@ -249,7 +248,7 @@ public String executeQuery(IConfiguration configuration, JsonNode query, PrintWr displayRequest(httpRequest, printWriter); final String result = httpRequestExecutor.executeHttp(httpRequest, false, telemetryManager); - printWriter.println(String.format("Result: %s", result)); + printWriter.println(String.format("Result: %n%s", result)); printWriter.flush(); return result; } @@ -271,14 +270,31 @@ boolean notNull(final JsonNode jsonNode) { * @param printWriter the PrintWriter to output the request details */ void displayRequest(final HttpRequest httpRequest, final PrintWriter printWriter) { - final String template = "%s: %s%n"; - printWriter.println(String.format("Hostname %s - Executing HTTP %s request:", httpRequest.getHostname(), httpRequest.getMethod())); + final String template = "%s: %s"; + printWriter.println( + String.format( + "Hostname %s - Executing %s %s request:", + httpRequest.getHostname(), + Boolean.TRUE.equals(httpRequest.getHttpConfiguration().getHttps()) ? "HTTPS" : "HTTP", + httpRequest.getMethod() + ) + ); + final Header header = httpRequest.getHeader(); + final Body body = httpRequest.getBody(); + final String authenticationToken = httpRequest.getAuthenticationToken(); + printWriter.println(String.format(template, "Url", httpRequest.getUrl())); - printWriter.println(String.format(template, "Path", httpRequest.getPath())); - printWriter.println(String.format(template, "Header", httpRequest.getHeader())); - printWriter.println(String.format(template, "Body", httpRequest.getBody())); - printWriter.println(String.format(template, "ResultContent", httpRequest.getResultContent())); - printWriter.println(String.format(template, "AuthenticationToken", httpRequest.getAuthenticationToken())); + if (header != null) { + printWriter.println(String.format(template, "Header", header.description())); + } + + if (body != null) { + printWriter.println(String.format(template, "Body", body.description())); + } + + if (authenticationToken != null) { + printWriter.println(String.format(template, "AuthenticationToken", authenticationToken)); + } printWriter.flush(); } } diff --git a/metricshub-http-extension/src/test/java/org/sentrysoftware/metricshub/extension/http/HttpExtensionTest.java b/metricshub-http-extension/src/test/java/org/sentrysoftware/metricshub/extension/http/HttpExtensionTest.java index 542bae363..526f74df0 100644 --- a/metricshub-http-extension/src/test/java/org/sentrysoftware/metricshub/extension/http/HttpExtensionTest.java +++ b/metricshub-http-extension/src/test/java/org/sentrysoftware/metricshub/extension/http/HttpExtensionTest.java @@ -66,7 +66,7 @@ class HttpExtensionTest { private static final String HTTP_GET = "GET"; private static final String TEST_HEADER = "Content-Type: application/xml"; private static final String AUTHENTICATION_TOKEN = "AGSDTZE5SZDF5FV7T82S4"; - private static final String HTTP_STATUS = "httpStatus"; + private static final String ALL = "all"; private static final String HTTP_SUCCESSFUL_RESPONSE = "Successful HTTP query"; /** @@ -543,14 +543,17 @@ void testProcessHttpSourceNoHttpConfiguration() { @Test void testExecuteQuery() { initHttp(); - HttpConfiguration httpConfiguration = (HttpConfiguration) telemetryManager.getHostConfiguration().getConfigurations().get(HttpConfiguration.class); + HttpConfiguration httpConfiguration = (HttpConfiguration) telemetryManager + .getHostConfiguration() + .getConfigurations() + .get(HttpConfiguration.class); ObjectNode httpQueryConfiguration = JsonNodeFactory.instance.objectNode(); httpQueryConfiguration.set("hostname", new TextNode(HOST_NAME)); httpQueryConfiguration.set("method", new TextNode("GET")); httpQueryConfiguration.set("url", new TextNode(TEST_URL)); httpQueryConfiguration.set("header", new TextNode(TEST_HEADER)); httpQueryConfiguration.set("body", new TextNode(TEST_BODY)); - httpQueryConfiguration.set("resultContent", new TextNode(HTTP_STATUS)); + httpQueryConfiguration.set("resultContent", new TextNode(ALL)); httpQueryConfiguration.set("authenticationToken", new TextNode(AUTHENTICATION_TOKEN)); HttpRequest httpRequest = HttpRequest @@ -561,7 +564,7 @@ void testExecuteQuery() { .url(TEST_URL) .header(TEST_HEADER, Map.of(), "", HOST_NAME) .body(TEST_BODY, Map.of(), "", HOST_NAME) - .resultContent(ResultContent.detect(HTTP_STATUS)) + .resultContent(ResultContent.detect(ALL)) .authenticationToken(AUTHENTICATION_TOKEN) .build(); @@ -571,7 +574,7 @@ void testExecuteQuery() { .executeHttp(eq(httpRequest), anyBoolean(), any(TelemetryManager.class)); PrintWriter printWriter = new PrintWriter(new StringWriter()); - + final String result = httpExtension.executeQuery(httpConfiguration, httpQueryConfiguration, printWriter); assertEquals(HTTP_SUCCESSFUL_RESPONSE, result); }