Integration tests for JMX Scraper (#1480)
Co-authored-by: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com>
This commit is contained in:
parent
ec5b64837a
commit
b0aae230cc
|
|
@ -31,23 +31,25 @@ public class JmxConnectorBuilderTest {
|
|||
|
||||
@Test
|
||||
void noAuth() {
|
||||
try (TestAppContainer app = new TestAppContainer().withNetwork(network).withJmxPort(9990)) {
|
||||
int port = PortSelector.getAvailableRandomPort();
|
||||
try (TestAppContainer app = new TestAppContainer().withHostAccessFixedJmxPort(port)) {
|
||||
app.start();
|
||||
testConnector(
|
||||
() -> JmxConnectorBuilder.createNew(app.getHost(), app.getMappedPort(9990)).build());
|
||||
() -> JmxConnectorBuilder.createNew(app.getHost(), app.getMappedPort(port)).build());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginPwdAuth() {
|
||||
int port = PortSelector.getAvailableRandomPort();
|
||||
String login = "user";
|
||||
String pwd = "t0p!Secret";
|
||||
try (TestAppContainer app =
|
||||
new TestAppContainer().withNetwork(network).withJmxPort(9999).withUserAuth(login, pwd)) {
|
||||
new TestAppContainer().withHostAccessFixedJmxPort(port).withUserAuth(login, pwd)) {
|
||||
app.start();
|
||||
testConnector(
|
||||
() ->
|
||||
JmxConnectorBuilder.createNew(app.getHost(), app.getMappedPort(9999))
|
||||
JmxConnectorBuilder.createNew(app.getHost(), app.getMappedPort(port))
|
||||
.userCredentials(login, pwd)
|
||||
.build());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.jmxscraper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Random;
|
||||
|
||||
/** Class used for finding random free network port from range 1024-65535 */
|
||||
public class PortSelector {
|
||||
private static final Random random = new Random(System.currentTimeMillis());
|
||||
|
||||
private static final int MIN_PORT = 1024;
|
||||
private static final int MAX_PORT = 65535;
|
||||
|
||||
private PortSelector() {}
|
||||
|
||||
/**
|
||||
* @return random available TCP port
|
||||
*/
|
||||
public static synchronized int getAvailableRandomPort() {
|
||||
int port;
|
||||
|
||||
do {
|
||||
port = random.nextInt(MAX_PORT - MIN_PORT + 1) + MIN_PORT;
|
||||
} while (!isPortAvailable(port));
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
private static boolean isPortAvailable(int port) {
|
||||
// see https://stackoverflow.com/a/13826145 for the chosen implementation
|
||||
try (Socket s = new Socket("localhost", port)) {
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,6 @@ import org.testcontainers.utility.MountableFile;
|
|||
public class TestAppContainer extends GenericContainer<TestAppContainer> {
|
||||
|
||||
private final Map<String, String> properties;
|
||||
private int port;
|
||||
private String login;
|
||||
private String pwd;
|
||||
|
||||
|
|
@ -44,11 +43,16 @@ public class TestAppContainer extends GenericContainer<TestAppContainer> {
|
|||
.withCommand("java", "-jar", "/app.jar");
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures app container for container-to-container access
|
||||
*
|
||||
* @param port mapped port to use
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public TestAppContainer withJmxPort(int port) {
|
||||
this.port = port;
|
||||
properties.put("com.sun.management.jmxremote.port", Integer.toString(port));
|
||||
return this.withExposedPorts(port);
|
||||
return this;
|
||||
}
|
||||
|
||||
@CanIgnoreReturnValue
|
||||
|
|
@ -58,9 +62,30 @@ public class TestAppContainer extends GenericContainer<TestAppContainer> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures app container for host-to-container access, port will be used as-is from host to
|
||||
* work-around JMX in docker. This is optional on Linux as there is a network route and the
|
||||
* container is accessible, but not on Mac where the container runs in an isolated VM.
|
||||
*
|
||||
* @param port port to use, must be available on host.
|
||||
* @return this
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public TestAppContainer withHostAccessFixedJmxPort(int port) {
|
||||
// To get host->container JMX connection working docker must expose JMX/RMI port under the same
|
||||
// port number. Because of this testcontainers' standard exposed port randomization approach
|
||||
// can't be used.
|
||||
// Explanation:
|
||||
// https://forums.docker.com/t/exposing-mapped-jmx-ports-from-multiple-containers/5287/6
|
||||
properties.put("com.sun.management.jmxremote.port", Integer.toString(port));
|
||||
properties.put("com.sun.management.jmxremote.rmi.port", Integer.toString(port));
|
||||
properties.put("java.rmi.server.hostname", getHost());
|
||||
addFixedExposedPort(port, port);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
// TODO: add support for ssl
|
||||
properties.put("com.sun.management.jmxremote.ssl", "false");
|
||||
|
||||
|
|
@ -92,11 +117,9 @@ public class TestAppContainer extends GenericContainer<TestAppContainer> {
|
|||
|
||||
this.withEnv("JAVA_TOOL_OPTIONS", confArgs);
|
||||
|
||||
logger().info("Test application JAVA_TOOL_OPTIONS = " + confArgs);
|
||||
logger().info("Test application JAVA_TOOL_OPTIONS = {}", confArgs);
|
||||
|
||||
super.start();
|
||||
|
||||
logger().info("Test application JMX port mapped to {}:{}", getHost(), getMappedPort(port));
|
||||
}
|
||||
|
||||
private static Path createPwdFile(String login, String pwd) {
|
||||
|
|
|
|||
|
|
@ -5,24 +5,19 @@
|
|||
|
||||
package io.opentelemetry.contrib.jmxscraper.target_systems;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.linecorp.armeria.server.ServerBuilder;
|
||||
import com.linecorp.armeria.server.grpc.GrpcService;
|
||||
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import io.opentelemetry.contrib.jmxscraper.JmxConnectorBuilder;
|
||||
import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer;
|
||||
import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest;
|
||||
import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse;
|
||||
import io.opentelemetry.proto.collector.metrics.v1.MetricsServiceGrpc;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
|
@ -35,8 +30,8 @@ import org.testcontainers.containers.Network;
|
|||
import org.testcontainers.containers.output.Slf4jLogConsumer;
|
||||
|
||||
public abstract class TargetSystemIntegrationTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TargetSystemIntegrationTest.class);
|
||||
private static final Logger targetSystemLogger = LoggerFactory.getLogger("TargetSystemContainer");
|
||||
private static final Logger jmxScraperLogger = LoggerFactory.getLogger("JmxScraperContainer");
|
||||
private static final String TARGET_SYSTEM_NETWORK_ALIAS = "targetsystem";
|
||||
private static String otlpEndpoint;
|
||||
|
||||
|
|
@ -54,6 +49,9 @@ public abstract class TargetSystemIntegrationTest {
|
|||
private JmxScraperContainer scraper;
|
||||
|
||||
private static final String OTLP_HOST = "host.testcontainers.internal";
|
||||
|
||||
// JMX communication only happens between container, and we don't have to use JMX
|
||||
// from host to container, we can use a fixed port.
|
||||
private static final int JMX_PORT = 9999;
|
||||
|
||||
@BeforeAll
|
||||
|
|
@ -93,27 +91,14 @@ public abstract class TargetSystemIntegrationTest {
|
|||
|
||||
target =
|
||||
createTargetContainer(JMX_PORT)
|
||||
.withLogConsumer(new Slf4jLogConsumer(logger))
|
||||
.withLogConsumer(new Slf4jLogConsumer(targetSystemLogger))
|
||||
.withNetwork(network)
|
||||
.withExposedPorts(JMX_PORT)
|
||||
.withNetworkAliases(TARGET_SYSTEM_NETWORK_ALIAS);
|
||||
target.start();
|
||||
|
||||
String targetHost = target.getHost();
|
||||
Integer targetPort = target.getMappedPort(JMX_PORT);
|
||||
logger.info(
|
||||
"Target system started, JMX port: {} mapped to {}:{}", JMX_PORT, targetHost, targetPort);
|
||||
|
||||
// TODO : wait for metrics to be sent and add assertions on what is being captured
|
||||
// for now we just test that we can connect to remote JMX using our client.
|
||||
try (JMXConnector connector = JmxConnectorBuilder.createNew(targetHost, targetPort).build()) {
|
||||
assertThat(connector.getMBeanServerConnection()).isNotNull();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
scraper =
|
||||
new JmxScraperContainer(otlpEndpoint)
|
||||
.withLogConsumer(new Slf4jLogConsumer(jmxScraperLogger))
|
||||
.withNetwork(network)
|
||||
.withService(TARGET_SYSTEM_NETWORK_ALIAS, JMX_PORT);
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ public class JmxConnectorBuilder {
|
|||
@SuppressWarnings("BanJNDI")
|
||||
private static JMXConnector doConnect(JMXServiceURL url, Map<String, Object> env)
|
||||
throws IOException {
|
||||
logger.info("Connecting to " + url);
|
||||
return JMXConnectorFactory.connect(url, env);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue