Java - как вызвать Java main () из нового потока процесса - PullRequest
1 голос
/ 08 апреля 2019

Я пытаюсь создать интеграционные тесты (ИТ) для приложения.В центре приложения находится сервер, написанный на Java, который настраивает очередь сообщений, из которой оно запрашивает сообщения, отправленные ему на определенный номер порта.Я хотел бы написать Интеграционный тест, который запускает некоторые сообщения на этом сервере / номер порта и проверяет ответ.

Ниже приведен полный список аргументов виртуальной машины, которые я запускаю при запуске сервера из Intellij вручную.Я могу запустить сервер таким образом, а затем запустить на нем свои тестовые сообщения, но я хотел бы преобразовать его в ИТ-тесты, чтобы я мог запускать / останавливать сервер программно в начале и в конце своих тестов.

Проблема в том, что я не знаю, как запустить серверное приложение из своего тестового класса.Таким образом, чтобы спросить более ясно, как запустить Java main () класса в его собственном потоке процесса.Я работаю в Intellij (2019.1) и Java 8. Должен ли я использовать ProcessBuilder или ExecutorService, может быть?

Я думаю, что могу использовать System.setProperty для некоторых аргументов VM, но не знаю, как указать -XX ... так что это будет вторая часть этого вопроса.

-Djava.endorsed.dirs=/Users/xxx/dev/src/repo/xxx/myapp/target/classes/lib/endorsed
       -Dmyapp.home=/private/var/tmp/myapp
                -Dmyapp.log.dir=/private/var/tmp
                          -Dmyapp.env=/Users/xxx/dev/src/repo/xxx/myapp/target/classes/etc/examples/environment-apa.sh
                         -Dsimplelogger.properties=/private/var/tmp/myapp/etc/simplelogger.properties
                           -server                   
        -XX:CompileThreshold=2500
                          -XX:+UseFastAccessorMethods
                          -Xss256k
                           -Xmx1g
                           -Xms512m

Я пытался реализовать это, используя ExecutorService

public class ServerTest {
    @Test
    public void shouldStartServerOk() {
        try{
            startServer();
        }catch(Exception e){
            e.printStackTrace();
            fail();
        }
    }

    private void startServer(){
        ExecutorService executor = Executors.newFixedThreadPool(1);

        Runnable runnableTask = new Runnable() {
            @Override
            public void run() {
                String [] args = new String[0];
                try {
                    System.setProperty("java.endorsed.dirs", "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed");
                    System.setProperty("myapp.home", "/private/var/tmp/myapp");
                    System.setProperty("myapp.log.dir", "/private/var/tmp");
                    System.setProperty("myapp.env", "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh");
                    System.setProperty("simplelogger.properties", "/private/var/tmp/myapp/etc/simplelogger.properties");
                    System.setProperty("-server", "TRUE");
                    MyApp.main(args);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        executor.execute(runnableTask);

        // shut down the executor manually
        //executor.shutdown();

    }

Но это непохоже, работает, хотя тест завершается зеленым.Когда я отлаживаю процесс, поток не входит в MyApp.main (аргументы).Странно, когда я просто пытаюсь запустить MyApp.main (args) отдельно от ExecutorService, тогда он запускается и работает нормально, пока я не нажму Stop в моей IDE.Это поведение, которое я хотел бы получить только от дополнительной способности запускать / останавливать процесс.

UPDATE-1: следуя комментариям @dmitrievanthony и @RealSkeptic, я попытался реализовать что-то в этом духе, основываясь на SO вопросе, Выполнение приложения Java в отдельном процессе / 636367 ,

public final class JavaProcess {

    private JavaProcess() {}

    public static int exec(Class klass) throws IOException,
            InterruptedException {
        String javaHome = System.getProperty("java.home");
        String javaBin = javaHome +
                File.separator + "bin" +
                File.separator + "java";
        String classpath = System.getProperty("java.class.path");
        String className = klass.getName();

        ProcessBuilder processBuilder = new ProcessBuilder(
                javaBin,
                "-cp",
                classpath,
                className
        );

        Map<String, String> env = processBuilder.environment();
        env.put("java.endorsed.dirs", "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed");
        env.put("myapp.home", "/private/var/tmp/myapp");
        env.put("myapp.log.dir", "/private/var/tmp");
        env.put("myapp.env", "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh");
        env.put("simplelogger.properties", "/private/var/tmp/myapp/etc/simplelogger.properties");
        env.put("-XX:CompileThreshold", "2500");
        env.put("-XX:+UseFastAccessorMethods", "");
        env.put("-Xss256k", "");
        env.put("-Xmx1g", "");
        env.put("-Xms512m", "");

        Process process = processBuilder.inheritIO().start();
        process.waitFor();
        return process.exitValue();
    }

и вызов его в моем тестовом классе myAppIT как int status = JavaProcess.exec(MyAapp.class);

Теперь я вижу свой классЗапуск «MyApp» - и может подтвердить, что поток процесса выполняется в моем классе MyApp.main ().Теперь проблема в том, что переменные System.env, которые я устанавливаю в ProcessBuilder, не отображаются в вызываемой программе, т.е.когда я печатаю в лог System.getProperty ("myapp.home"), он возвращает значение NULL, хотя я могу подтвердить, что он установлен так, как показано в коде - у кого-нибудь есть идеи по этому поводу, пожалуйста?

ОБНОВЛЕНИЕ 2: я пытаюсь реализовать предложение @RealSkeptic и передать аргументы аналогично передаче аргументов командной строки, как показано в фрагменте кода ниже.Теперь я получаю исключение Error: Could not find or load main class xxx.xxx.xxx.xxx.MyApp -Djava.endorsed.dirs=.Users.xxx.dev.src.gitlab.myapp.myapp.target.classes.lib.endorsed, одна проблема, которую я вижу, состоит в том, что прямые косые черты пути были переведены в «.».Путь должен выглядеть следующим образом: Djava.endorsed.dirs=/Users/xxx/dev/src/gitlab/myapp/myapp/target/classes/lib/endorsed

ProcessBuilder processBuilder = new ProcessBuilder(
                javaBin,
                "-cp",
                classpath,
                className + " " +
                "-Djava.endorsed.dirs=" + "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed " +
                "-Dmyapp.home=/private/var/tmp/myapp " +
                "-Dmyapp.log.dir=/private/var/tmp" +
                "-Dmyapp.env=/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh " +
                "-Dsimplelogger.properties=/private/var/tmp/myapp/etc/simplelogger.properties " +
                "-server " +
                "-XX:CompileThreshold=2500 " +
                "-XX:+UseFastAccessorMethods " +
                "-Xss256k " +
                "-Xmx1g " +
                "-Xms512m"
        );

Update-3 после последнего комментария от @RealSkeptic Я изменил свой код (см. Ниже), и теперь это работает.

ProcessBuilder processBuilder = new ProcessBuilder(
                javaBin,
                "-cp",
                classpath,
                "-Djava.endorsed.dirs=" + "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed",
                "-Dmyapp.home=/private/var/tmp/myapp",
                "-Dmyapp.log.dir=/private/var/tmp",
                "-Dmyapp.env=/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh",
                "-Dsimplelogger.properties=/private/var/tmp/myapp/etc/simplelogger.properties ",
                "-server",
                "-XX:CompileThreshold=2500",
                "-XX:+UseFastAccessorMethods",
                "-Xss256k",
                "-Xmx1g",
                "-Xms512m",
                className
        );

1 Ответ

0 голосов
/ 10 апреля 2019

Ниже скопировано с ОБНОВЛЕНИЯ-3, которое я отправляю как ответ.Спасибо тем, кто ответил, и особенно @ RealSkeptic.

ProcessBuilder processBuilder = new ProcessBuilder(
                javaBin,
                "-cp",
                classpath,
                "-Djava.endorsed.dirs=" + "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed",
                "-Drrc.home=/private/var/tmp/myapp",
                "-Drrc.log.dir=/private/var/tmp",
                "-Drrc.env=/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh",
                "-Dsimplelogger.properties=/private/var/tmp/myapp/etc/simplelogger.properties ",
                "-server",
                "-XX:CompileThreshold=2500",
                "-XX:+UseFastAccessorMethods",
                "-Xss256k",
                "-Xmx1g",
                "-Xms512m",
                className
        );

Я произвел рефакторинг вышеупомянутого, чтобы поместить каждый из аргументов в Список, чтобы вызов ProcessBuilder сократился до,

ProcessBuilder processBuilder = new ProcessBuilder(arguments); Process process = processBuilder.inheritIO().start();

Чтобы остановить процесс, вам просто нужно позвонить process.destroy();

...