diff --git a/wsclient/src/main/java/org/hpccsystems/ws/client/BaseHPCCWsClient.java b/wsclient/src/main/java/org/hpccsystems/ws/client/BaseHPCCWsClient.java index c26f75ce4..0dfe94b5e 100644 --- a/wsclient/src/main/java/org/hpccsystems/ws/client/BaseHPCCWsClient.java +++ b/wsclient/src/main/java/org/hpccsystems/ws/client/BaseHPCCWsClient.java @@ -40,13 +40,28 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.semconv.HttpAttributes; +import io.opentelemetry.semconv.ServerAttributes; + /** - * Defines functionality common to all HPCC Systmes web service clients. + * Defines functionality common to all HPCC Systems web service clients. * * Typically implemented by specialized HPCC Web service clients. */ public abstract class BaseHPCCWsClient extends DataSingleton { + public static final String PROJECT_NAME = "WsClient"; + private static OpenTelemetry globalOTel = null; /** Constant log */ protected static final Logger log = LogManager.getLogger(BaseHPCCWsClient.class); /** Constant DEAFULTECLWATCHPORT="8010" */ @@ -164,6 +179,53 @@ private String getTargetHPCCBuildVersionString() throws Exception } + public SpanBuilder getWsClientSpanBuilder(String spanName) + { + SpanBuilder spanBuilder = getWsClientTracer().spanBuilder(spanName) + .setAttribute(ServerAttributes.SERVER_ADDRESS, wsconn.getHost()) + .setAttribute(ServerAttributes.SERVER_PORT, Long.getLong(wsconn.getPort())) + .setAttribute(HttpAttributes.HTTP_REQUEST_METHOD, HttpAttributes.HttpRequestMethodValues.GET) + .setSpanKind(SpanKind.CLIENT); + + return spanBuilder; + } + + static public void injectCurrentSpanTraceParentHeader(Stub clientStub) + { + if (clientStub != null) + { + injectCurrentSpanTraceParentHeader(clientStub._getServiceClient().getOptions()); + } + } + + static public void injectCurrentSpanTraceParentHeader(Options options) + { + if (options != null) + { + W3CTraceContextPropagator.getInstance().inject(Context.current(), options, Options::setProperty); + } + } + + /** + * Performs all Otel initialization + */ + private void initOTel() + { + /* + * If using the OpenTelemetry SDK, you may want to instantiate the OpenTelemetry toprovide configuration, for example of Resource or Sampler. See OpenTelemetrySdk and OpenTelemetrySdk.builder for information on how to construct theSDK's OpenTelemetry implementation. + * WARNING: Due to the inherent complications around initialization order involving this classand its single global instance, we strongly recommend *not* using GlobalOpenTelemetry unless youhave a use-case that absolutely requires it. Please favor using instances of OpenTelemetrywherever possible. + * If you are using the OpenTelemetry javaagent, it is generally best to only callGlobalOpenTelemetry.get() once, and then pass the resulting reference where you need to use it. + */ + globalOTel = GlobalOpenTelemetry.get(); + } + + public Tracer getWsClientTracer() + { + if (globalOTel == null) + initOTel(); + + return globalOTel.getTracer(PROJECT_NAME); + } /** * All instances of HPCCWsXYZClient should utilize this init function * Attempts to establish the target HPCC build version and its container mode @@ -175,36 +237,55 @@ private String getTargetHPCCBuildVersionString() throws Exception */ protected boolean initBaseWsClient(Connection connection, boolean fetchVersionAndContainerMode) { + initOTel(); + boolean success = true; initErrMessage = ""; setActiveConnectionInfo(connection); if (fetchVersionAndContainerMode) { - try + Span fetchHPCCVerSpan = getWsClientSpanBuilder("FetchHPCCVersion").setSpanKind(SpanKind.INTERNAL).startSpan(); + try (Scope scope = fetchHPCCVerSpan.makeCurrent()) { - targetHPCCBuildVersion = new Version(getTargetHPCCBuildVersionString()); + try + { + targetHPCCBuildVersion = new Version(getTargetHPCCBuildVersionString()); + } + catch (Exception e) + { + initErrMessage = "BaseHPCCWsClient: Could not stablish target HPCC bulid version, review all HPCC connection values"; + if (!e.getLocalizedMessage().isEmpty()) + initErrMessage = initErrMessage + "\n" + e.getLocalizedMessage(); + success = false; + } } - catch (Exception e) + finally { - initErrMessage = "BaseHPCCWsClient: Could not stablish target HPCC bulid version, review all HPCC connection values"; - if (!e.getLocalizedMessage().isEmpty()) - initErrMessage = initErrMessage + "\n" + e.getLocalizedMessage(); - - success = false; + fetchHPCCVerSpan.setStatus(success ? StatusCode.OK : StatusCode.ERROR, initErrMessage); + fetchHPCCVerSpan.end(); } - try + Span fetchHPCCContainerMode = getWsClientSpanBuilder("FetchHPCCContainerMode").startSpan(); + try (Scope scope = fetchHPCCContainerMode.makeCurrent()) { - targetsContainerizedHPCC = getTargetHPCCIsContainerized(wsconn); + try + { + targetsContainerizedHPCC = getTargetHPCCIsContainerized(wsconn); + } + catch (Exception e) + { + initErrMessage = initErrMessage + "\nBaseHPCCWsClient: Could not determine target HPCC Containerization mode, review all HPCC connection values"; + if (!e.getLocalizedMessage().isEmpty()) + initErrMessage = initErrMessage + "\n" + e.getLocalizedMessage(); + + success = false; + } } - catch (Exception e) + finally { - initErrMessage = initErrMessage + "\nBaseHPCCWsClient: Could not determine target HPCC Containerization mode, review all HPCC connection values"; - if (!e.getLocalizedMessage().isEmpty()) - initErrMessage = initErrMessage + "\n" + e.getLocalizedMessage(); - - success = false; + fetchHPCCContainerMode.setStatus(success ? StatusCode.OK : StatusCode.ERROR, initErrMessage); + fetchHPCCContainerMode.end(); } } if (!initErrMessage.isEmpty()) @@ -401,7 +482,10 @@ public String getInitError() protected Stub verifyStub() throws Exception { if (stub != null) + { + injectCurrentSpanTraceParentHeader(stub); return stub; + } else throw new Exception("WS Client Stub not available." + (hasInitError() ? "\n" + initErrMessage : "")); } @@ -687,6 +771,7 @@ protected void handleEspExceptions(ArrayOfEspExceptionWrapper exp, String messag if (message != null && !message.isEmpty()) exp.setWsClientMessage(message); log.error(exp.toString()); + throw exp; } diff --git a/wsclient/src/main/java/org/hpccsystems/ws/client/HPCCWsClient.java b/wsclient/src/main/java/org/hpccsystems/ws/client/HPCCWsClient.java index e5a7de7da..0979c8d85 100644 --- a/wsclient/src/main/java/org/hpccsystems/ws/client/HPCCWsClient.java +++ b/wsclient/src/main/java/org/hpccsystems/ws/client/HPCCWsClient.java @@ -19,7 +19,6 @@ import org.hpccsystems.ws.client.utils.Utils; import org.hpccsystems.ws.client.wrappers.ArrayOfECLExceptionWrapper; import org.hpccsystems.ws.client.wrappers.gen.filespray.ProgressResponseWrapper; -import org.hpccsystems.ws.client.wrappers.gen.wstopology.TpGroupQueryResponseWrapper; import org.hpccsystems.ws.client.wrappers.gen.wstopology.TpGroupWrapper; import org.hpccsystems.ws.client.wrappers.wsworkunits.WorkunitWrapper; diff --git a/wsclient/src/main/java/org/hpccsystems/ws/client/HPCCWsWorkUnitsClient.java b/wsclient/src/main/java/org/hpccsystems/ws/client/HPCCWsWorkUnitsClient.java index 829644a84..92a27d690 100644 --- a/wsclient/src/main/java/org/hpccsystems/ws/client/HPCCWsWorkUnitsClient.java +++ b/wsclient/src/main/java/org/hpccsystems/ws/client/HPCCWsWorkUnitsClient.java @@ -100,6 +100,10 @@ import org.hpccsystems.ws.client.wrappers.wsworkunits.WorkunitWrapper; import org.hpccsystems.ws.client.wrappers.wsworkunits.WsWorkunitsClientStubWrapper; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Scope; + /** * Facilitates ECL WorkUnit related actions. * @@ -303,7 +307,6 @@ public void fastWURefresh(WorkunitWrapper wu) throws Exception, ArrayOfEspExcept request.setCount(1); WUQueryResponse response = null; - try { response = ((WsWorkunits) stub).wUQuery(request); @@ -326,7 +329,8 @@ public void fastWURefresh(WorkunitWrapper wu) throws Exception, ArrayOfEspExcept { ECLWorkunit[] eclWorkunit = response.getWorkunits().getECLWorkunit(); - if (eclWorkunit != null && eclWorkunit.length == 1) wu.update(eclWorkunit[0]); + if (eclWorkunit != null && eclWorkunit.length == 1) + wu.update(eclWorkunit[0]); } if (previousState != getStateID(wu)) @@ -2551,18 +2555,27 @@ public List deleteQueries(Set querynames, String clu */ public boolean ping() throws Exception { - verifyStub(); - - Ping request = new Ping(); - - try + Span span = getWsClientSpanBuilder("WsWUClient_Ping").startSpan(); + try (Scope scope = span.makeCurrent()) { - ((WsWorkunitsStub) stub).ping(request); + verifyStub(); // must be called within span scope for proper context propagation + + Ping request = new Ping(); + try + { + ((WsWorkunitsStub) stub).ping(request); + span.setStatus(StatusCode.OK); + } + catch (Exception e) + { + span.recordException(e); + log.error(e.getLocalizedMessage()); + return false; + } } - catch (Exception e) + finally { - log.error(e.getLocalizedMessage()); - return false; + span.end(); } return true; diff --git a/wsclient/src/main/java/org/hpccsystems/ws/client/utils/Connection.java b/wsclient/src/main/java/org/hpccsystems/ws/client/utils/Connection.java index a28da183d..c5acac2e7 100644 --- a/wsclient/src/main/java/org/hpccsystems/ws/client/utils/Connection.java +++ b/wsclient/src/main/java/org/hpccsystems/ws/client/utils/Connection.java @@ -12,9 +12,20 @@ import java.util.Base64; import java.util.Base64.Decoder; import java.util.Base64.Encoder; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.hpccsystems.ws.client.BaseHPCCWsClient; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Scope; +import io.opentelemetry.semconv.HttpAttributes; +import io.opentelemetry.semconv.ServerAttributes; /** * Represents and structures connection information. @@ -205,6 +216,9 @@ public int hashCode() private StringBuffer baseUrl; private StringBuffer uriAndParams; + // Note: this pattern is very basic and is only meant to extract hostnames from URLs + public final static Pattern URL_HOSTNAME_PATTERN = Pattern.compile("((https?|ftp|file):\\/\\/)?(?([\\da-z\\.\\-_]+)(\\.[a-z\\.]{2,6})?)(:\\d{2,6})?.*"); + /** Constant CONNECT_TIMEOUT_PARAM="connecttimeoutmillis" */ final static public String CONNECT_TIMEOUT_PARAM = "connecttimeoutmillis"; /** Constant READ_TIMEOUT_PARAM="readtimeoutmillis" */ @@ -287,7 +301,27 @@ public static boolean isSslProtocol(String protocol) */ public Connection(String connectionstring) throws MalformedURLException { - URL theurl = new URL(connectionstring); + URL theurl = null; + try + { + theurl = new URL(connectionstring); + } + catch (MalformedURLException e) + { + Matcher matcher = URL_HOSTNAME_PATTERN.matcher(connectionstring); + if (matcher.matches()) + { + String hostName = matcher.group("hostname"); + if (hostName.contains("_")) + { + throw new MalformedURLException("Invalid URL: Hostname contains invalid underscores: '" + connectionstring + "': " + e.getMessage()); + } + } + else + { + throw e; + } + } setProtocol(theurl.getProtocol()); @@ -1028,39 +1062,61 @@ public String sendHTTPRequest(String uri, String method) throws Exception URL url = new URL (getBaseUrl() + (uri != null && uri.startsWith("/") ? "" : "/") + uri); - HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); //throws IOException - - Connection.log.info("Sending HTTP " + method + "Request to:" + url.toString()); + Span sendHTTPReqSpan = GlobalOpenTelemetry.get().getTracer(BaseHPCCWsClient.PROJECT_NAME) + .spanBuilder(method.toUpperCase() + " " + url.toExternalForm()) + .setAttribute(ServerAttributes.SERVER_ADDRESS, getHost()) + .setAttribute(ServerAttributes.SERVER_PORT, Long.getLong(getPort())) + .setAttribute(HttpAttributes.HTTP_REQUEST_METHOD, method) + .setSpanKind(SpanKind.CLIENT) + .startSpan(); - if (hasCredentials()) - { - httpURLConnection.setRequestProperty("Authorization", getBasicAuthString()); - } + HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); //throws IOException - httpURLConnection.setRequestMethod(method); //throws ProtocolException + Connection.log.info("Sending HTTP " + method + "Request to:" + url.toString()); - int responseCode = httpURLConnection.getResponseCode(); //throws IOException + if (hasCredentials()) + { + httpURLConnection.setRequestProperty("Authorization", getBasicAuthString()); + sendHTTPReqSpan.setAttribute("hasCredentials", true); + } + else + { + sendHTTPReqSpan.setAttribute("hasCredentials", false); + } - Connection.log.info("HTTP Response code: " + responseCode); + try (Scope scope = sendHTTPReqSpan.makeCurrent()) + { + httpURLConnection.setRequestProperty("traceparent", Utils.getCurrentSpanTraceParentHeader()); + httpURLConnection.setRequestMethod(method); //throws ProtocolException - if (responseCode == HttpURLConnection.HTTP_OK) //success - { - BufferedReader in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())); //throws IOException - String inputLine; - StringBuffer response = new StringBuffer(); + int responseCode = httpURLConnection.getResponseCode(); //throws IOException + sendHTTPReqSpan.setAttribute("http.response.status_code", responseCode); + Connection.log.info("HTTP Response code: " + responseCode); - while ((inputLine = in.readLine()) != null) // throws IOException - { - response.append(inputLine); - } + if (responseCode == HttpURLConnection.HTTP_OK) //success + { + BufferedReader in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())); //throws IOException + String inputLine; + StringBuffer response = new StringBuffer(); - in.close(); //throws IOException + while ((inputLine = in.readLine()) != null) // throws IOException + { + response.append(inputLine); + } - return response.toString(); - } - else - { - throw new IOException("HTTP request failed! Code (" + responseCode + ") " + httpURLConnection.getResponseMessage() ); - } + in.close(); //throws IOException + sendHTTPReqSpan.setStatus(StatusCode.OK); + return response.toString(); + } + else + { + sendHTTPReqSpan.setStatus(StatusCode.ERROR); + throw new IOException("HTTP request failed! Code (" + responseCode + ") " + httpURLConnection.getResponseMessage() ); + } + } + finally + { + sendHTTPReqSpan.end(); + } } } diff --git a/wsclient/src/main/java/org/hpccsystems/ws/client/utils/Utils.java b/wsclient/src/main/java/org/hpccsystems/ws/client/utils/Utils.java index df7a56162..bf71bc6e9 100644 --- a/wsclient/src/main/java/org/hpccsystems/ws/client/utils/Utils.java +++ b/wsclient/src/main/java/org/hpccsystems/ws/client/utils/Utils.java @@ -16,7 +16,9 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; @@ -39,6 +41,11 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapSetter; + /** * Provides multiple functions which support HPCCWsClient actions. * @@ -1121,4 +1128,25 @@ public static String trimTrailing(String originalStr) return originalStr.substring(0,strIndex+1); } + + /** + * Returns traceparent value for Open Telemetry based context propagation + * @return traceparent of current span if valid, otherwise invalid traceparent header value + */ + static public String getCurrentSpanTraceParentHeader() + { + String traceparent = null; + Span currentSpan = Span.current(); + if (currentSpan != null && currentSpan.getSpanContext().isValid()) + { + Map carrier = new HashMap<>(); + TextMapSetter> setter = Map::put; + W3CTraceContextPropagator.getInstance().inject(Context.current(), carrier, setter); + + traceparent = carrier.getOrDefault("traceparent", "00-" + currentSpan.getSpanContext().getTraceId() + "-" + currentSpan.getSpanContext().getSpanId() + "-00"); + carrier.clear(); + } + + return traceparent; + } } diff --git a/wsclient/src/test/java/org/hpccsystems/ws/client/BaseRemoteTest.java b/wsclient/src/test/java/org/hpccsystems/ws/client/BaseRemoteTest.java index 14b0f23ce..077fba31e 100644 --- a/wsclient/src/test/java/org/hpccsystems/ws/client/BaseRemoteTest.java +++ b/wsclient/src/test/java/org/hpccsystems/ws/client/BaseRemoteTest.java @@ -30,28 +30,27 @@ HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®. import java.util.concurrent.Executors; import java.util.concurrent.Future; -import org.hpccsystems.ws.client.HPCCWsWorkUnitsClient; -import org.hpccsystems.ws.client.wrappers.wsworkunits.WorkunitWrapper; -import org.hpccsystems.ws.client.HPCCWsClient; import org.hpccsystems.ws.client.HPCCWsTopologyClient.TopologyGroupQueryKind; import org.hpccsystems.ws.client.platform.Platform; import org.hpccsystems.ws.client.utils.Connection; import org.hpccsystems.ws.client.wrappers.gen.wstopology.TpGroupWrapper; -import org.junit.Assume; +import org.hpccsystems.ws.client.wrappers.wsworkunits.WorkunitWrapper; import org.junit.Assert; +import org.junit.Assume; import org.junit.BeforeClass; import org.junit.experimental.categories.Category; -import java.net.URL; - -import java.nio.file.Paths; -import java.nio.file.Path; -import java.nio.file.Files; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; @Category(org.hpccsystems.commons.annotations.RemoteTests.class) public abstract class BaseRemoteTest { public static Exception initializationException = null; + private final static String INSTRUMENTED_LIB_NAME = "WsClientJUnitSuite"; protected static Platform platform; protected static HPCCWsClient wsclient; @@ -72,6 +71,7 @@ public abstract class BaseRemoteTest protected final static int testThreadCount = Integer.parseInt(System.getProperty("testthreadcount", "10")); public static final String DEFAULTHPCCFILENAME = "benchmark::all_types::200kb"; + protected static OpenTelemetry globalOTel = null; /* * Code to generate superfile with default file as subfile @@ -109,8 +109,39 @@ public static void initCheck() Assume.assumeTrue("Error initializing test suite: " + exceptionMessage, initializationException == null); } + public static Tracer getRemoteTestTracer() + { + return globalOTel.getTracer(INSTRUMENTED_LIB_NAME); + } + + public static SpanBuilder getRemoteTestTraceBuilder(String spanName) + { + return getRemoteTestTracer().spanBuilder(spanName); + } + public static void initialize() throws Exception { + if (Boolean.getBoolean("otel.java.global-autoconfigure.enabled")) + { + System.out.println("OpenTelemetry autoconfiguration enabled with following values."); + System.out.println("If any of these options are not provided, they will defalt to values which could require additional CLASSPATH dependancies."); + System.out.println("If missing dependancies arise, test will halt!"); + System.out.println(" otel.traces.exporter sys property: "+System.getProperty("otel.traces.exporter")); + System.out.println(" OTEL_TRACES_EXPORTER Env var: " + System.getenv("OTEL_TRACES_EXPORTER")); + System.out.println(" OTEL_TRACES_SAMPLER Env var: " + System.getenv("OTEL_TRACES_SAMPLER")); + System.out.println(" otel.traces.sampler sys property: "+System.getProperty("otel.traces.sampler")); + System.out.println(" otel.logs.exporter: "+ System.getProperty("otel.logs.exporter")); + System.out.println(" OTEL_LOGS_EXPORTER Env var: " + System.getenv("OTEL_LOGS_EXPORTER")); + System.out.println(" otel.metrics.exporter: "+ System.getProperty("otel.metrics.exporter")); + System.out.println(" OTEL_METRICS_EXPORTER Env var: " + System.getenv("OTEL_METRICS_EXPORTER")); + + globalOTel = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); + } + else + { + globalOTel = GlobalOpenTelemetry.get(); + } + // This allows testing against locally created self signed certs to work. // In production certs will need to be created valid hostnames javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier( @@ -226,7 +257,7 @@ public boolean verify(String hostname,javax.net.ssl.SSLSession sslSession) } else { - System.out.println("RemoteTest: 'roxiegroupname': '" + roxieclustername + "'"); + System.out.println("RemoteTest: 'roxiegroupname': '" + roxieclustername + "'"); } } catch (Exception e) diff --git a/wsclient/src/test/java/org/hpccsystems/ws/client/WSWorkunitsTest.java b/wsclient/src/test/java/org/hpccsystems/ws/client/WSWorkunitsTest.java index deb12aca5..5457ba293 100644 --- a/wsclient/src/test/java/org/hpccsystems/ws/client/WSWorkunitsTest.java +++ b/wsclient/src/test/java/org/hpccsystems/ws/client/WSWorkunitsTest.java @@ -38,6 +38,11 @@ HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®. import org.junit.Test; import org.junit.runners.MethodSorters; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Scope; + @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class WSWorkunitsTest extends BaseRemoteTest { @@ -82,18 +87,30 @@ public void testSharedWsWUgets() throws InterruptedException @Test public void stageA_ping() throws Exception { - try - { - Assert.assertTrue(client.ping()); - } - catch (AxisFault e) + Span pingSpan = getRemoteTestTraceBuilder("WsWUTests-PingTest").setSpanKind(SpanKind.CLIENT).startSpan(); + + try (Scope innerScope = pingSpan.makeCurrent()) { - e.printStackTrace(); - Assert.fail(); + try + { + Assert.assertTrue(client.ping()); + pingSpan.setStatus(StatusCode.OK); + } + catch (AxisFault e) + { + pingSpan.recordException(e); + e.printStackTrace(); + Assert.fail(); + } + catch (Exception e) + { + pingSpan.recordException(e); + Assert.fail(e.toString()); + } } - catch (Exception e) + finally { - Assert.fail(e.toString()); + pingSpan.end(); } } diff --git a/wsclient/src/test/java/org/hpccsystems/ws/client/platform/test/PlatformTester.java b/wsclient/src/test/java/org/hpccsystems/ws/client/platform/test/PlatformTester.java index d71e776bd..8596fb40b 100644 --- a/wsclient/src/test/java/org/hpccsystems/ws/client/platform/test/PlatformTester.java +++ b/wsclient/src/test/java/org/hpccsystems/ws/client/platform/test/PlatformTester.java @@ -12,6 +12,7 @@ import org.hpccsystems.ws.client.HPCCWsDFUClient; import org.hpccsystems.ws.client.HPCCWsSMCClient; import org.hpccsystems.ws.client.HPCCWsSQLClient; +import org.hpccsystems.ws.client.HPCCWsWorkUnitsClient; import org.hpccsystems.ws.client.extended.HPCCWsAttributesClient; import org.hpccsystems.ws.client.gen.axis2.wsdfu.v1_39.SecAccessType; import org.hpccsystems.ws.client.platform.PhysicalFile; @@ -31,6 +32,12 @@ import org.junit.experimental.categories.Category; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; + @Category(org.hpccsystems.commons.annotations.RemoteTests.class) public class PlatformTester { @@ -175,221 +182,256 @@ else if (currentParam.matches(WSSQLPORTPATTERN)) try { - Platform platform = Platform.get(prot, hpccServer, port, user, pass); - - HPCCWsSMCClient wssmc = platform.getWsClient().getWsSMCClient(); - - Version targetVersion = new Version(wssmc.getHPCCBuild()); - - Version v = platform.getVersion(); - System.out.println(v.toString()); - - HPCCWsClient client1 = platform.checkOutHPCCWsClient(); - HPCCWsClient client2 = platform.checkOutHPCCWsClient(); - HPCCWsClient client3 = platform.checkOutHPCCWsClient(); - HPCCWsClient client4 = platform.checkOutHPCCWsClient(); - if (platform.validateHPCCWsClient(client1)) + OpenTelemetry globalOTel = null; + if (Boolean.getBoolean("otel.java.global-autoconfigure.enabled")) { - HPCCWsAttributesClient wsAttributesClient1 = client1.getWsAttributesClient(); + System.out.println("OpenTelemetry autoconfiguration enabled with following values."); + System.out.println("If any of these options are not provided, they will defalt to values which could require additional CLASSPATH dependancies."); + System.out.println("If missing dependancies arise, test will halt!"); + System.out.println(" otel.traces.exporter sys property: "+System.getProperty("otel.traces.exporter")); + System.out.println(" OTEL_TRACES_EXPORTER Env var: " + System.getenv("OTEL_TRACES_EXPORTER")); + System.out.println(" OTEL_TRACES_SAMPLER Env var: " + System.getenv("OTEL_TRACES_SAMPLER")); + System.out.println(" otel.traces.sampler sys property: "+System.getProperty("otel.traces.sampler")); + System.out.println(" otel.logs.exporter: "+ System.getProperty("otel.logs.exporter")); + System.out.println(" OTEL_LOGS_EXPORTER Env var: " + System.getenv("OTEL_LOGS_EXPORTER")); + System.out.println(" otel.metrics.exporter: "+ System.getProperty("otel.metrics.exporter")); + System.out.println(" OTEL_METRICS_EXPORTER Env var: " + System.getenv("OTEL_METRICS_EXPORTER")); + + globalOTel = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); } - - if (platform.validateHPCCWsClient(client2)) + else { - HPCCWsAttributesClient wsAttributesClient2 = client2.getWsAttributesClient(); - platform.expireHPCCWsClient(client2); - if (!platform.validateHPCCWsClient(client2)) - System.out.println("not validated"); - else - wsAttributesClient2 = client2.getWsAttributesClient(); + globalOTel = GlobalOpenTelemetry.get(); } - HPCCWsAttributesClient wsAttributesClient3 = client3.getWsAttributesClient(); - HPCCWsAttributesClient wsAttributesClient4 = client4.getWsAttributesClient(); + Span rootSpan = globalOTel.getTracer("PlatformTester").spanBuilder("rootspan").startSpan(); + try (Scope scope = rootSpan.makeCurrent()) + { + Platform platform = Platform.get(prot, hpccServer, port, user, pass); - platform.checkInHPCCWsClient(client2); - platform.checkInHPCCWsClient(client3); - platform.checkInHPCCWsClient(client4); + HPCCWsSMCClient wssmc = platform.getWsClient().getWsSMCClient(); - org.hpccsystems.ws.client.platform.DropZone[] dropzones = platform.getDropZones(); - for(int i = 0; i < dropzones.length; i++) - { - System.out.println("Dropzone Name: " + dropzones[i].getName()); - System.out.println("Dropzone Directory: " + dropzones[i].getDirectory()); - System.out.println("Dropzone Machines: "); - PhysicalMachine [] dzmachines = dropzones[i].getMachines(); - for (PhysicalMachine physicalmachine : dzmachines) + Version targetVersion = new Version(wssmc.getHPCCBuild()); + + Version v = platform.getVersion(); + System.out.println(v.toString()); + + HPCCWsClient client1 = platform.checkOutHPCCWsClient(); + HPCCWsClient client2 = platform.checkOutHPCCWsClient(); + HPCCWsClient client3 = platform.checkOutHPCCWsClient(); + HPCCWsClient client4 = platform.checkOutHPCCWsClient(); + if (platform.validateHPCCWsClient(client1)) { - System.out.println("\tName: " + physicalmachine.getName()); - System.out.println("\tConfigured Address: " + physicalmachine.getConfigNetaddress()); - System.out.println("\tActual Address: " + physicalmachine.getNetaddress()); - System.out.println("\tOS: " + physicalmachine.getOSName()); - boolean isWin = physicalmachine.getOSCode() == HPCCEnvOSCode.MachineOsW2K; - System.out.println("\tFiles: "); - - PhysicalFile[] physicalFiles = physicalmachine.getFiles(); - for (PhysicalFile physicalFile : physicalFiles) + HPCCWsAttributesClient wsAttributesClient1 = client1.getWsAttributesClient(); + } + + if (platform.validateHPCCWsClient(client2)) + { + HPCCWsAttributesClient wsAttributesClient2 = client2.getWsAttributesClient(); + platform.expireHPCCWsClient(client2); + if (!platform.validateHPCCWsClient(client2)) + System.out.println("not validated"); + else + wsAttributesClient2 = client2.getWsAttributesClient(); + } + + HPCCWsAttributesClient wsAttributesClient3 = client3.getWsAttributesClient(); + HPCCWsAttributesClient wsAttributesClient4 = client4.getWsAttributesClient(); + + platform.checkInHPCCWsClient(client2); + platform.checkInHPCCWsClient(client3); + platform.checkInHPCCWsClient(client4); + + org.hpccsystems.ws.client.platform.DropZone[] dropzones = platform.getDropZones(); + for(int i = 0; i < dropzones.length; i++) + { + System.out.println("Dropzone Name: " + dropzones[i].getName()); + System.out.println("Dropzone Directory: " + dropzones[i].getDirectory()); + System.out.println("Dropzone Machines: "); + PhysicalMachine [] dzmachines = dropzones[i].getMachines(); + for (PhysicalMachine physicalmachine : dzmachines) { - String name = physicalFile.getName() + (physicalFile.getIsDir() ? (!isWin ? "/" : "\\") : ""); - System.out.format( "\t\t%-30s %15s %15s\n", name, physicalFile.getIsDir() ? "" : physicalFile.getFilesize() , physicalFile.getModifiedtime()); + System.out.println("\tName: " + physicalmachine.getName()); + System.out.println("\tConfigured Address: " + physicalmachine.getConfigNetaddress()); + System.out.println("\tActual Address: " + physicalmachine.getNetaddress()); + System.out.println("\tOS: " + physicalmachine.getOSName()); + boolean isWin = physicalmachine.getOSCode() == HPCCEnvOSCode.MachineOsW2K; + System.out.println("\tFiles: "); + + PhysicalFile[] physicalFiles = physicalmachine.getFiles(); + for (PhysicalFile physicalFile : physicalFiles) + { + String name = physicalFile.getName() + (physicalFile.getIsDir() ? (!isWin ? "/" : "\\") : ""); + System.out.format( "\t\t%-30s %15s %15s\n", name, physicalFile.getIsDir() ? "" : physicalFile.getFilesize() , physicalFile.getModifiedtime()); + } } } - } - HPCCFileSprayClient fsc = client1.getFileSprayClient(); - List dzLocal = fsc.fetchLocalDropZones(); - if (dzLocal != null && dzLocal.size() > 0) - { - System.out.println("fetchLocalDropZones test ..."); - for(int i = 0; i < dzLocal.size(); i++) + HPCCFileSprayClient fsc = client1.getFileSprayClient(); + List dzLocal = fsc.fetchLocalDropZones(); + if (dzLocal != null && dzLocal.size() > 0) { - DropZoneWrapper thisDZ = dzLocal.get(i); - boolean islinux = thisDZ.getLinux().equals("false") ? false : true; - - System.out.println("DropZone[" + i + "]"); - System.out.println("\tName: " + thisDZ.getName()); - System.out.println("\tPath: " + thisDZ.getPath()); - System.out.println("\tNetAddress: " + thisDZ.getNetAddress()); - System.out.println("\tComputer: " + thisDZ.getComputer()); - System.out.println("\tIsLinux: " + thisDZ.getLinux()); - - List pfs = fsc.listFiles(dzLocal.get(i).getNetAddress(), dzLocal.get(i).getPath(), null); - System.out.println("\tFile Listing:"); - if (pfs != null && pfs.size()> 0) + System.out.println("fetchLocalDropZones test ..."); + for(int i = 0; i < dzLocal.size(); i++) { - for(int fileindex = 0; fileindex < pfs.size(); fileindex++) + DropZoneWrapper thisDZ = dzLocal.get(i); + boolean islinux = thisDZ.getLinux().equals("false") ? false : true; + + System.out.println("DropZone[" + i + "]"); + System.out.println("\tName: " + thisDZ.getName()); + System.out.println("\tPath: " + thisDZ.getPath()); + System.out.println("\tNetAddress: " + thisDZ.getNetAddress()); + System.out.println("\tComputer: " + thisDZ.getComputer()); + System.out.println("\tIsLinux: " + thisDZ.getLinux()); + + List pfs = fsc.listFiles(dzLocal.get(i).getNetAddress(), dzLocal.get(i).getPath(), null); + System.out.println("\tFile Listing:"); + if (pfs != null && pfs.size()> 0) { - String name = pfs.get(fileindex).getName() + (pfs.get(fileindex).getIsDir() ? (islinux ? "/" : "\\") : ""); - System.out.format( "\t\t%-30s %15s %15s\n", name, pfs.get(fileindex).getIsDir() ? "" : pfs.get(fileindex).getFilesize() , pfs.get(fileindex).getModifiedtime()); + for(int fileindex = 0; fileindex < pfs.size(); fileindex++) + { + String name = pfs.get(fileindex).getName() + (pfs.get(fileindex).getIsDir() ? (islinux ? "/" : "\\") : ""); + System.out.format( "\t\t%-30s %15s %15s\n", name, pfs.get(fileindex).getIsDir() ? "" : pfs.get(fileindex).getFilesize() , pfs.get(fileindex).getModifiedtime()); + } } } } - } - List dzByAddress = fsc.fetchDropZones(hpccServer); - if (dzByAddress != null && dzByAddress.size() > 0) - { - System.out.println("fetchDropZones by address test ..."); - for (int i = 0; i < dzByAddress.size(); i++) + List dzByAddress = fsc.fetchDropZones(hpccServer); + if (dzByAddress != null && dzByAddress.size() > 0) { - DropZoneWrapper thisDZ = dzByAddress.get(i); - boolean islinux = thisDZ.getLinux().equals("false") ? false : true; - - System.out.println("DropZone[" + i + "]"); - System.out.println("\tName: " + thisDZ.getName()); - System.out.println("\tNetAddress: " + thisDZ.getNetAddress()); - System.out.println("\tPath: " + thisDZ.getPath()); - System.out.println("\tComputer: " + thisDZ.getComputer()); - System.out.println("\tIsLinux: " + thisDZ.getLinux()); - - List pfs = fsc.listFiles(thisDZ.getNetAddress(), thisDZ.getPath(), null); - System.out.println("\tFile Listing:"); - if (pfs != null && pfs.size() > 0) + System.out.println("fetchDropZones by address test ..."); + for (int i = 0; i < dzByAddress.size(); i++) { - for (int fileindex = 0; fileindex < pfs.size(); fileindex++) { - PhysicalFileStructWrapper thisfile = pfs.get(fileindex); - String name = thisfile.getName() + (thisfile.getIsDir() ? (islinux ? "/" : "\\") : ""); - System.out.format("\t\t%-30s %15s %15s\n", name, thisfile.getIsDir() ? "" : thisfile.getFilesize(), thisfile.getModifiedtime()); + DropZoneWrapper thisDZ = dzByAddress.get(i); + boolean islinux = thisDZ.getLinux().equals("false") ? false : true; + + System.out.println("DropZone[" + i + "]"); + System.out.println("\tName: " + thisDZ.getName()); + System.out.println("\tNetAddress: " + thisDZ.getNetAddress()); + System.out.println("\tPath: " + thisDZ.getPath()); + System.out.println("\tComputer: " + thisDZ.getComputer()); + System.out.println("\tIsLinux: " + thisDZ.getLinux()); + + List pfs = fsc.listFiles(thisDZ.getNetAddress(), thisDZ.getPath(), null); + System.out.println("\tFile Listing:"); + if (pfs != null && pfs.size() > 0) + { + for (int fileindex = 0; fileindex < pfs.size(); fileindex++) { + PhysicalFileStructWrapper thisfile = pfs.get(fileindex); + String name = thisfile.getName() + (thisfile.getIsDir() ? (islinux ? "/" : "\\") : ""); + System.out.format("\t\t%-30s %15s %15s\n", name, thisfile.getIsDir() ? "" : thisfile.getFilesize(), thisfile.getModifiedtime()); + } } } } - } - List pfs = fsc.listFiles(dzByAddress.get(0).getNetAddress(), dzByAddress.get(0).getPath(), null); + List pfs = fsc.listFiles(dzByAddress.get(0).getNetAddress(), dzByAddress.get(0).getPath(), null); - // Test file download - System.out.println("Download test ..."); - String fileName = null; - for (int i = 0; pfs != null && i < pfs.size(); i++) - { - if (pfs.get(i).getIsDir() == false - && pfs.get(i).getFilesize() < 4 * 1024 * 1024) // Only download small files for the test + // Test file download + System.out.println("Download test ..."); + String fileName = null; + for (int i = 0; pfs != null && i < pfs.size(); i++) { - fileName = pfs.get(i).getName(); - break; + if (pfs.get(i).getIsDir() == false + && pfs.get(i).getFilesize() < 4 * 1024 * 1024) // Only download small files for the test + { + fileName = pfs.get(i).getName(); + break; + } } - } - if (fileName != null) - { - System.out.println("Attempting to download: " + fileName + " from DropZone"); - String outputFile = System.getProperty("java.io.tmpdir") + File.separator + fileName; - System.out.println("Output File: " + outputFile); + if (fileName != null) + { + System.out.println("Attempting to download: " + fileName + " from DropZone"); + String outputFile = System.getProperty("java.io.tmpdir") + File.separator + fileName; + System.out.println("Output File: " + outputFile); - File tmpFile = new File(outputFile); + File tmpFile = new File(outputFile); - long bytesTransferred = fsc.downloadFile(tmpFile,dzByAddress.get(0),fileName); - if (bytesTransferred <= 0) - { - System.out.println("Download failed."); + long bytesTransferred = fsc.downloadFile(tmpFile,dzByAddress.get(0),fileName); + if (bytesTransferred <= 0) + { + System.out.println("Download failed."); + } + else + { + System.out.println("File Download Test: Bytes transferred: " + bytesTransferred); + } } else { - System.out.println("File Download Test: Bytes transferred: " + bytesTransferred); + System.out.println("Skipping file download test. No small files found in DropZone."); } - } - else - { - System.out.println("Skipping file download test. No small files found in DropZone."); - } - String tmpPeopleFile = System.getProperty("java.io.tmpdir") + File.separator + "people"; - writeFile( tmpPeopleFile, Persons.data, false); + String tmpPeopleFile = System.getProperty("java.io.tmpdir") + File.separator + "people"; + writeFile( tmpPeopleFile, Persons.data, false); - String tmpAccountFile = System.getProperty("java.io.tmpdir") + File.separator + "account"; - writeFile( tmpAccountFile, Accounts.data, false); + String tmpAccountFile = System.getProperty("java.io.tmpdir") + File.separator + "account"; + writeFile( tmpAccountFile, Accounts.data, false); - int pport = HPCCWsAttributesClient.getServiceWSDLPort(); - HPCCWsClient connector = platform.checkOutHPCCWsClient(); - connector.setVerbosemode(true); - System.out.println("wsdfu ver: " + connector.getwsDFUClientClientVer()); - HPCCWsDFUClient wsDFUClient = connector.getWsDFUClient(); - if (v.getMajor() == 7 && v.getMinor() == 0) - { - System.out.println("Attempting file access on HPCC 7.0.x cluster..."); - DFUFileAccessInfoWrapper a = wsDFUClient.getFileAccess(SecAccessType.Read, "benchmark::integer::2mb", "thor_160", 120, "random", true, true, true); - } - else if (v.getMajor() == 7 && v.getMinor() > 0) - { - System.out.println("Attempting file access on HPCC 7.0.x cluster..."); - wsDFUClient.getFileAccess("benchmark::integer::2mb", "thor_160", 120, "random"); - } - platform.checkInHPCCWsClient(connector); + int pport = HPCCWsAttributesClient.getServiceWSDLPort(); + HPCCWsClient connector = platform.checkOutHPCCWsClient(); + connector.setVerbosemode(true); + System.out.println("wswu ver: " + connector.getWsWorkunitsClientVer()); + HPCCWsWorkUnitsClient wsWUClient = connector.getWsWorkunitsClient(); + wsWUClient.ping(); - connector = platform.checkOutHPCCWsClient(); - System.out.println("wsfileio ver: " + connector.getWsFileIOClientVer()); - System.out.println("wssmc ver: " + connector.getWsSMCClientClientVer()); - System.out.println("wspackageprocess ver: " + connector.getHPCCWsPackageProcessClientVer()); + System.out.println("wsdfu ver: " + connector.getwsDFUClientClientVer()); - List newgetFileDataColumns = wsDFUClient.getFileMetaData(".::kw_test_sup", null); + HPCCWsDFUClient wsDFUClient = connector.getWsDFUClient(); + if (v.getMajor() == 7 && v.getMinor() == 0) + { + System.out.println("Attempting file access on HPCC 7.0.x cluster..."); + DFUFileAccessInfoWrapper a = wsDFUClient.getFileAccess(SecAccessType.Read, "benchmark::integer::2mb", "thor_160", 120, "random", true, true, true); + } + else if (v.getMajor() == 7 && v.getMinor() > 0) + { + System.out.println("Attempting file access on HPCC 7.0.x cluster..."); + wsDFUClient.getFileAccess("benchmark::integer::2mb", "thor_160", 120, "random"); + } + platform.checkInHPCCWsClient(connector); - for (DFUDataColumnWrapper wrapper : newgetFileDataColumns) - { - System.out.println("Col name: " + wrapper.getColumnLabel() + " ecl: " + wrapper.getColumnEclType() + " col type " + wrapper.getColumnType()); - } + connector = platform.checkOutHPCCWsClient(); + System.out.println("wsfileio ver: " + connector.getWsFileIOClientVer()); + System.out.println("wssmc ver: " + connector.getWsSMCClientClientVer()); + System.out.println("wspackageprocess ver: " + connector.getHPCCWsPackageProcessClientVer()); - try - { - //WSSQL Test - HPCCWsSQLClient wsSQLClient = platform.getWsClient().getWsSQLClient(wssqlport); - String s = "CREATE TABLE newtablename (FirstName VARCHAR(15), LastName VARCHAR(25), MiddleName VARCHAR(15) ,StreetAddress VARCHAR(42), city VARCHAR(20), state VARCHAR(2), zip VARCHAR(5)) LOAD DATA INFILE 'people-small' CONNECTION '10.0.2.15' DIRECTORY '/var/lib/HPCCSystems/mydropzone' INTO TABLE newtablename"; - ExecuteSQLResponseWrapper executeSQLFullResponse = wsSQLClient.executeSQLFullResponse(s, "thor", "thor", Integer.valueOf(0), Integer.valueOf(0),Integer.valueOf(0), false, false, "me", Integer.valueOf(-1)); - System.out.println(executeSQLFullResponse.getResult()); - - s = "SELECT * from newtablename where state = 'FL' limit 10;"; - executeSQLFullResponse = wsSQLClient.executeSQLFullResponse(s, "thor", "thor", Integer.valueOf(0), Integer.valueOf(0),Integer.valueOf(0), false, false, "me", Integer.valueOf(-1)); - System.out.println(executeSQLFullResponse.getResult()); - } - catch (java.net.ConnectException e) - { - System.out.println("Could not connect to WsSQL on port: " + wssqlport + "\n>>" + e.getLocalizedMessage()); - } - catch (ArrayOfBaseExceptionWrapper e) - { - e.printStackTrace(); + List newgetFileDataColumns = wsDFUClient.getFileMetaData(".::kw_test_sup", null); + + for (DFUDataColumnWrapper wrapper : newgetFileDataColumns) + { + System.out.println("Col name: " + wrapper.getColumnLabel() + " ecl: " + wrapper.getColumnEclType() + " col type " + wrapper.getColumnType()); + } + + try + { + //WSSQL Test + HPCCWsSQLClient wsSQLClient = platform.getWsClient().getWsSQLClient(wssqlport); + String s = "CREATE TABLE newtablename (FirstName VARCHAR(15), LastName VARCHAR(25), MiddleName VARCHAR(15) ,StreetAddress VARCHAR(42), city VARCHAR(20), state VARCHAR(2), zip VARCHAR(5)) LOAD DATA INFILE 'people-small' CONNECTION '10.0.2.15' DIRECTORY '/var/lib/HPCCSystems/mydropzone' INTO TABLE newtablename"; + ExecuteSQLResponseWrapper executeSQLFullResponse = wsSQLClient.executeSQLFullResponse(s, "thor", "thor", Integer.valueOf(0), Integer.valueOf(0),Integer.valueOf(0), false, false, "me", Integer.valueOf(-1)); + System.out.println(executeSQLFullResponse.getResult()); + + s = "SELECT * from newtablename where state = 'FL' limit 10;"; + executeSQLFullResponse = wsSQLClient.executeSQLFullResponse(s, "thor", "thor", Integer.valueOf(0), Integer.valueOf(0),Integer.valueOf(0), false, false, "me", Integer.valueOf(-1)); + System.out.println(executeSQLFullResponse.getResult()); + } + catch (java.net.ConnectException e) + { + System.out.println("Could not connect to WsSQL on port: " + wssqlport + "\n>>" + e.getLocalizedMessage()); + } + catch (ArrayOfBaseExceptionWrapper e) + { + e.printStackTrace(); + } + catch (Exception e) + { + System.out.println("Encountered issue while testing WsSQL on port: " + wssqlport + "\n>>" + e.getLocalizedMessage()); + } } - catch (Exception e) + finally { - System.out.println("Encountered issue while testing WsSQL on port: " + wssqlport + "\n>>" + e.getLocalizedMessage()); + rootSpan.end(); } } @@ -401,7 +443,6 @@ else if (v.getMajor() == 7 && v.getMinor() > 0) { System.out.println("\n****WsClient HPCC platform tester has finished****\n" ); } - } } diff --git a/wsclient/src/test/java/org/hpccsystems/ws/client/utils/ConnectionTest.java b/wsclient/src/test/java/org/hpccsystems/ws/client/utils/ConnectionTest.java index edfc9d640..278b40540 100644 --- a/wsclient/src/test/java/org/hpccsystems/ws/client/utils/ConnectionTest.java +++ b/wsclient/src/test/java/org/hpccsystems/ws/client/utils/ConnectionTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.*; import java.net.MalformedURLException; +import java.util.regex.Matcher; import org.junit.Test; @@ -107,4 +108,27 @@ public void testInvalidProtHostPort() throws MalformedURLException assertFalse(con.getIsHttps()); assertEquals(con.getProtocol(), http); } + + @Test + public void hostNamePatternTest() throws MalformedURLException + { + // Note: we want to test improved error messaging with underscores, but not all versions + // of Java throw an exception for underscores in hostnames. + // So we are testing the pattern instead + String[] urls = { + "https://invalid_host_name.test:8010?params", + "https://invalid_host_name.test:8010", + "http://invalid_host_name.test:8010", + "invalid_host_name.test:8010", + "invalid_host_name.test" + }; + + String hostName = "invalid_host_name.test"; + for (String url : urls) + { + Matcher matcher = Connection.URL_HOSTNAME_PATTERN.matcher(url); + assertTrue(matcher.matches()); + assertEquals(matcher.group("hostname"), hostName); + } + } }