Added Native API test

This commit is contained in:
Andrei Pangin
2024-07-26 14:41:40 +03:00
parent 78123a85a7
commit 321a712ff8
5 changed files with 141 additions and 29 deletions
+1 -1
View File
@@ -147,7 +147,7 @@ public class Runner {
log.log(Level.INFO, "Running " + testName + "...");
String testLogDir = logDir.isEmpty() ? null : logDir + '/' + testName;
try (TestProcess p = new TestProcess(test, testLogDir, currentOs.getLibExt())) {
try (TestProcess p = new TestProcess(test, currentOs, testLogDir)) {
Object holder = (m.getModifiers() & Modifier.STATIC) == 0 ? m.getDeclaringClass().newInstance() : null;
m.invoke(holder, p);
log.info("OK");
+3 -1
View File
@@ -16,7 +16,9 @@ import java.lang.annotation.Target;
@Repeatable(Tests.class)
public @interface Test {
Class<?> mainClass();
String[] sh() default {};
Class<?> mainClass() default Test.class;
String args() default "";
+56 -27
View File
@@ -58,24 +58,10 @@ public class TestProcess implements Closeable {
private final Map<String, File> tmpFiles = new HashMap<>();
private final int timeout = 30;
public TestProcess(Test test, String logDir, String libExt) throws Exception {
public TestProcess(Test test, Os currentOs, String logDir) throws Exception {
this.logDir = logDir;
List<String> cmd = new ArrayList<>();
cmd.add(System.getProperty("java.home") + "/bin/java");
cmd.add("-cp");
cmd.add(System.getProperty("java.class.path"));
if (test.debugNonSafepoints()) {
cmd.add("-XX:+UnlockDiagnosticVMOptions");
cmd.add("-XX:+DebugNonSafepoints");
}
addArgs(cmd, test.jvmArgs());
if (!test.agentArgs().isEmpty()) {
cmd.add("-agentpath:build/lib/libasyncProfiler." + libExt + "=" + substituteFiles(test.agentArgs()));
}
cmd.add(test.mainClass().getName());
addArgs(cmd, test.args());
List<String> cmd = buildCommandLine(test, currentOs);
log.log(Level.FINE, "Running " + cmd);
ProcessBuilder pb = new ProcessBuilder(cmd).inheritIO();
@@ -87,8 +73,39 @@ public class TestProcess implements Closeable {
}
this.p = pb.start();
// Give the JVM some time to initialize
Thread.sleep(700);
if (cmd.get(0).endsWith("java")) {
// Give the JVM some time to initialize
Thread.sleep(700);
}
}
private List<String> buildCommandLine(Test test, Os currentOs) {
List<String> cmd = new ArrayList<>();
String[] sh = test.sh();
if (sh.length > 0) {
cmd.add("/bin/sh");
cmd.add("-e");
cmd.add("-c");
cmd.add(substituteFiles(String.join(";", sh)));
} else {
cmd.add(System.getProperty("java.home") + "/bin/java");
cmd.add("-cp");
cmd.add(System.getProperty("java.class.path"));
if (test.debugNonSafepoints()) {
cmd.add("-XX:+UnlockDiagnosticVMOptions");
cmd.add("-XX:+DebugNonSafepoints");
}
addArgs(cmd, test.jvmArgs());
if (!test.agentArgs().isEmpty()) {
cmd.add("-agentpath:build/lib/libasyncProfiler." + currentOs.getLibExt() + "=" +
substituteFiles(test.agentArgs()));
}
cmd.add(test.mainClass().getName());
addArgs(cmd, test.args());
}
return cmd;
}
private String getExtFromFile(File file) {
@@ -124,7 +141,7 @@ public class TestProcess implements Closeable {
StringBuffer sb = new StringBuffer();
do {
File f = createTempFile(m.group(1));
File f = createTempFile(m.group(1), m.group(2));
m.appendReplacement(sb, f.getPath());
} while (m.find());
@@ -132,13 +149,17 @@ public class TestProcess implements Closeable {
}
private File createTempFile(String fileId) {
try {
File f = File.createTempFile("ap-" + fileId.substring(1), null);
tmpFiles.put(fileId, f);
return f;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return createTempFile(fileId, null);
}
private File createTempFile(String fileId, String ext) {
return tmpFiles.computeIfAbsent(fileId, key -> {
try {
return File.createTempFile("ap-" + key.substring(1), ext);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}
private void clearTempFiles() {
@@ -199,6 +220,10 @@ public class TestProcess implements Closeable {
}
}
public int exitCode() {
return p.exitValue();
}
public Output waitForExit(String fileId) throws TimeoutException, InterruptedException {
waitForExit(p, timeout);
return readFile(fileId);
@@ -239,8 +264,12 @@ public class TestProcess implements Closeable {
return readFile(PROFOUT);
}
public File getFile(String fileId) {
return tmpFiles.get(fileId);
}
public Output readFile(String fileId) {
File f = tmpFiles.get(fileId);
File f = getFile(fileId);
try (Stream<String> stream = Files.lines(f.toPath())) {
return new Output(stream.toArray(String[]::new));
} catch (IOException e) {
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright The async-profiler authors
* SPDX-License-Identifier: Apache-2.0
*/
package test.c;
import one.profiler.test.Os;
import one.profiler.test.Output;
import one.profiler.test.Test;
import one.profiler.test.TestProcess;
public class CTests {
// TODO: Make the test work on macOS
@Test(sh = {"gcc -Isrc test/test/c/nativeApi.c -ldl -o%c", "%c %f.jfr"}, output = true, os = Os.LINUX)
public void nativeApi(TestProcess p) throws Exception {
Output out = p.waitForExit(TestProcess.STDOUT);
assert p.exitCode() == 0;
assert out.contains("Starting profiler");
assert out.contains("Stopping profiler");
assert p.getFile("%f").length() > 0;
}
}
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright The async-profiler authors
* SPDX-License-Identifier: Apache-2.0
*/
#include <dlfcn.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "asprof.h"
static void fail(const char* msg) {
fprintf(stderr, "%s\n", msg);
exit(1);
}
static void uninterruptible_sleep(unsigned long ms) {
struct timespec ts = {ms / 1000, (ms % 1000) * 1000000};
while (nanosleep(&ts, &ts) < 0 && errno == EINTR) ;
}
int main(int argc, char** argv) {
if (argc < 2) {
fail("Too few arguments");
}
void* lib = dlopen("build/lib/libasyncProfiler.so", RTLD_NOW);
if (lib == NULL) {
fail("Failed to load libasyncProfiler.so");
}
asprof_init_t asprof_init = dlsym(lib, "asprof_init");
asprof_init();
char cmd[4096];
snprintf(cmd, sizeof(cmd), "start,event=cpu,interval=1ms,wall=10ms,cstack=dwarf,loglevel=debug,file=%s", argv[1]);
printf("Starting profiler\n");
asprof_execute_t asprof_execute = dlsym(lib, "asprof_execute");
asprof_error_t err = asprof_execute(cmd, NULL);
if (err != NULL) {
fail(err);
}
uninterruptible_sleep(2000);
printf("Stopping profiler\n");
err = asprof_execute("stop", NULL);
if (err != NULL) {
fail(err);
}
return 0;
}