Skip to content

Commit aecf5ff

Browse files
authored
Merge pull request #4 from SylvainJuge/tomcat-it
Bootstrap integration tests
2 parents 39b6341 + 1a6533e commit aecf5ff

File tree

11 files changed

+540
-389
lines changed

11 files changed

+540
-389
lines changed

jmx-scraper/build.gradle.kts

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ testing {
2929
dependencies {
3030
implementation("org.testcontainers:junit-jupiter")
3131
implementation("org.slf4j:slf4j-simple")
32+
implementation("com.linecorp.armeria:armeria-junit5")
33+
implementation("com.linecorp.armeria:armeria-grpc")
34+
implementation("io.opentelemetry.proto:opentelemetry-proto:0.20.0-alpha")
3235
}
3336
}
3437
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.jmxscraper;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
11+
import java.time.Duration;
12+
import java.util.ArrayList;
13+
import java.util.HashSet;
14+
import java.util.List;
15+
import java.util.Locale;
16+
import java.util.Set;
17+
import org.testcontainers.containers.GenericContainer;
18+
import org.testcontainers.containers.wait.strategy.Wait;
19+
import org.testcontainers.utility.MountableFile;
20+
21+
/** Test container that allows to execute {@link JmxScraper} in an isolated container */
22+
public class JmxScraperContainer extends GenericContainer<JmxScraperContainer> {
23+
24+
private final String endpoint;
25+
private final Set<String> targetSystems;
26+
private String serviceUrl;
27+
private int intervalMillis;
28+
private final Set<String> customYamlFiles;
29+
30+
public JmxScraperContainer(String otlpEndpoint) {
31+
super("openjdk:8u272-jre-slim");
32+
33+
String scraperJarPath = System.getProperty("shadow.jar.path");
34+
assertThat(scraperJarPath).isNotNull();
35+
36+
this.withCopyFileToContainer(MountableFile.forHostPath(scraperJarPath), "/scraper.jar")
37+
.waitingFor(
38+
Wait.forLogMessage(".*JMX scraping started.*", 1)
39+
.withStartupTimeout(Duration.ofSeconds(10)));
40+
41+
this.endpoint = otlpEndpoint;
42+
this.targetSystems = new HashSet<>();
43+
this.customYamlFiles = new HashSet<>();
44+
this.intervalMillis = 1000;
45+
}
46+
47+
@CanIgnoreReturnValue
48+
public JmxScraperContainer withTargetSystem(String targetSystem) {
49+
targetSystems.add(targetSystem);
50+
return this;
51+
}
52+
53+
@CanIgnoreReturnValue
54+
public JmxScraperContainer withIntervalMillis(int intervalMillis) {
55+
this.intervalMillis = intervalMillis;
56+
return this;
57+
}
58+
59+
@CanIgnoreReturnValue
60+
public JmxScraperContainer withService(String host, int port) {
61+
// TODO: adding a way to provide 'host:port' syntax would make this easier for end users
62+
this.serviceUrl =
63+
String.format(
64+
Locale.getDefault(), "service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi", host, port);
65+
return this;
66+
}
67+
68+
@CanIgnoreReturnValue
69+
public JmxScraperContainer withCustomYaml(String yamlPath) {
70+
this.customYamlFiles.add(yamlPath);
71+
return this;
72+
}
73+
74+
@Override
75+
public void start() {
76+
// for now only configure through JVM args
77+
List<String> arguments = new ArrayList<>();
78+
arguments.add("java");
79+
arguments.add("-Dotel.exporter.otlp.endpoint=" + endpoint);
80+
81+
if (!targetSystems.isEmpty()) {
82+
arguments.add("-Dotel.jmx.target.system=" + String.join(",", targetSystems));
83+
}
84+
85+
if (serviceUrl == null) {
86+
throw new IllegalStateException("Missing service URL");
87+
}
88+
arguments.add("-Dotel.jmx.service.url=" + serviceUrl);
89+
arguments.add("-Dotel.jmx.interval.milliseconds=" + intervalMillis);
90+
91+
if (!customYamlFiles.isEmpty()) {
92+
for (String yaml : customYamlFiles) {
93+
this.withCopyFileToContainer(MountableFile.forClasspathResource(yaml), yaml);
94+
}
95+
arguments.add("-Dotel.jmx.config=" + String.join(",", customYamlFiles));
96+
}
97+
98+
arguments.add("-jar");
99+
arguments.add("/scraper.jar");
100+
101+
this.withCommand(arguments.toArray(new String[0]));
102+
103+
logger().info("Starting scraper with command: " + String.join(" ", arguments));
104+
105+
super.start();
106+
}
107+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.jmxscraper;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
import java.io.IOException;
11+
import java.nio.charset.StandardCharsets;
12+
import java.nio.file.Files;
13+
import java.nio.file.Path;
14+
import java.nio.file.Paths;
15+
import java.time.Duration;
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
import java.util.stream.Collectors;
19+
import org.testcontainers.containers.GenericContainer;
20+
import org.testcontainers.containers.wait.strategy.Wait;
21+
import org.testcontainers.shaded.com.google.errorprone.annotations.CanIgnoreReturnValue;
22+
import org.testcontainers.utility.MountableFile;
23+
24+
/** Test container that allows to execute {@link TestApp} in an isolated container */
25+
public class TestAppContainer extends GenericContainer<TestAppContainer> {
26+
27+
private final Map<String, String> properties;
28+
private int port;
29+
private String login;
30+
private String pwd;
31+
32+
public TestAppContainer() {
33+
super("openjdk:8u272-jre-slim");
34+
35+
this.properties = new HashMap<>();
36+
37+
String appJar = System.getProperty("app.jar.path");
38+
assertThat(Paths.get(appJar)).isNotEmptyFile().isReadable();
39+
40+
this.withCopyFileToContainer(MountableFile.forHostPath(appJar), "/app.jar")
41+
.waitingFor(
42+
Wait.forLogMessage(TestApp.APP_STARTED_MSG + "\\n", 1)
43+
.withStartupTimeout(Duration.ofSeconds(5)))
44+
.withCommand("java", "-jar", "/app.jar");
45+
}
46+
47+
@CanIgnoreReturnValue
48+
public TestAppContainer withJmxPort(int port) {
49+
this.port = port;
50+
properties.put("com.sun.management.jmxremote.port", Integer.toString(port));
51+
return this.withExposedPorts(port);
52+
}
53+
54+
@CanIgnoreReturnValue
55+
public TestAppContainer withUserAuth(String login, String pwd) {
56+
this.login = login;
57+
this.pwd = pwd;
58+
return this;
59+
}
60+
61+
@Override
62+
public void start() {
63+
64+
// TODO: add support for ssl
65+
properties.put("com.sun.management.jmxremote.ssl", "false");
66+
67+
if (pwd == null) {
68+
properties.put("com.sun.management.jmxremote.authenticate", "false");
69+
} else {
70+
properties.put("com.sun.management.jmxremote.authenticate", "true");
71+
72+
Path pwdFile = createPwdFile(login, pwd);
73+
this.withCopyFileToContainer(MountableFile.forHostPath(pwdFile), "/jmx.password");
74+
properties.put("com.sun.management.jmxremote.password.file", "/jmx.password");
75+
76+
Path accessFile = createAccessFile(login);
77+
this.withCopyFileToContainer(MountableFile.forHostPath(accessFile), "/jmx.access");
78+
properties.put("com.sun.management.jmxremote.access.file", "/jmx.access");
79+
}
80+
81+
String confArgs =
82+
properties.entrySet().stream()
83+
.map(
84+
e -> {
85+
String s = "-D" + e.getKey();
86+
if (!e.getValue().isEmpty()) {
87+
s += "=" + e.getValue();
88+
}
89+
return s;
90+
})
91+
.collect(Collectors.joining(" "));
92+
93+
this.withEnv("JAVA_TOOL_OPTIONS", confArgs);
94+
95+
logger().info("Test application JAVA_TOOL_OPTIONS = " + confArgs);
96+
97+
super.start();
98+
99+
logger().info("Test application JMX port mapped to {}:{}", getHost(), getMappedPort(port));
100+
}
101+
102+
private static Path createPwdFile(String login, String pwd) {
103+
try {
104+
Path path = Files.createTempFile("test", ".pwd");
105+
writeLine(path, String.format("%s %s", login, pwd));
106+
return path;
107+
} catch (IOException e) {
108+
throw new RuntimeException(e);
109+
}
110+
}
111+
112+
private static Path createAccessFile(String login) {
113+
try {
114+
Path path = Files.createTempFile("test", ".pwd");
115+
writeLine(path, String.format("%s %s", login, "readwrite"));
116+
return path;
117+
} catch (IOException e) {
118+
throw new RuntimeException(e);
119+
}
120+
}
121+
122+
private static void writeLine(Path path, String line) throws IOException {
123+
line = line + "\n";
124+
Files.write(path, line.getBytes(StandardCharsets.UTF_8));
125+
}
126+
}

0 commit comments

Comments
 (0)