Процесс уничтожения, запущенный org.apache.commons.executor
Я начал выполнение testng.xml через библиотеку apache commons executor, выполнив следующий код:
DefaultExecuteResultHandler resultHandler;
ExecuteWatchdog watchdog;
final Executor executor;
resultHandler = new DefaultExecuteResultHandler();
watchdog = new ExecuteWatchdog(-1L);
executor = new DefaultExecutor();
executor.setStreamHandler(new PumpStreamHandler(new LogOutputStream() {
@Override
protected void processLine(final String line, @SuppressWarnings("unused") int level) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
if (line.toLowerCase().indexOf("error") > -1) {
textArea.append(line+"\n");
} else if (line.toLowerCase().indexOf("warn") > -1) {
textArea.append(line+"\n");
} else {
textArea.append(line+"\n");
}
}
});
}
}));
executor.setExitValue(1);
executor.setWatchdog(watchdog);
executor.execute(cl, resultHandler);
Но я хочу дать кнопку остановки, чтобы остановить этот процесс. Я старался:
executor.getWatchdog().destroyProcess();
Но это разрушает только сторожевой таймер. Однако testng.xml, который я начал, продолжает работать в фоновом режиме. Я хочу разрушить процесс, который я дал в команде. Это возможно?
1 ответ
Причина, по которой ваше решение не убивает созданную JVM, возможно, в том, что вы вызываете cmd.exe
и изнутри именно там вы, вероятно, порождаете JVM. Поэтому, когда вы вызываете destroyProcess()
Я верю cmd.exe
это убивает но не java.exe
,
Вы должны попробовать изменить командную строку на что-то вроде ниже:
java -cp D:\MyProject\Utilities*;D:\MyProject\bin org.testng.TestNG D:\MyProject\testng.xml
Вот решение, которое не использует исполнителя Apache commons executor для этого, но управляет всем в пределах одной JVM, а также предоставляет способ получения вывода и вывода ошибок из TestNG.
В этом решении используются API-интерфейсы TestNG.
Основной тестовый прогон, который использует TestNG для запуска тестов, в другом потоке выглядит следующим образом
import org.testng.TestNG;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SimpleTestRunner {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.err.println("***Main Thread running in Thread [" + Thread.currentThread().getId() + "]***");
ExecutorService service = Executors.newCachedThreadPool();
WorkerThread thread = new WorkerThread(SampleTestClass.class);
List<Future<ExecutionResults>> allResults = service.invokeAll(Collections.singletonList(thread));
service.shutdown();
ExecutionResults result = allResults.get(0).get();
System.err.println("******Printing the TestNG output******");
System.err.println(result);
System.err.println("**************************************");
}
public static class WorkerThread implements Callable<ExecutionResults> {
private Class<?>[] classes;
WorkerThread(Class<?>... classes) {
this.classes = classes;
}
@Override
public ExecutionResults call() throws Exception {
System.err.println("***Worker Thread running in Thread [" + Thread.currentThread().getId() + "]***");
TestNG testNG = new TestNG();
ExecutionResults results;
testNG.setVerbose(2);
ConsoleCapturer capturer = new ConsoleCapturer();
testNG.setTestClasses(classes);
try {
capturer.start();
testNG.run();
} finally {
ConsoleCapturer.CapturedData data = capturer.stop();
results = new ExecutionResults(data, testNG.getStatus());
}
return results;
}
}
public static class ExecutionResults {
private ConsoleCapturer.CapturedData data;
private int status;
public ExecutionResults(ConsoleCapturer.CapturedData data, int status) {
this.data = data;
this.status = status;
}
public ConsoleCapturer.CapturedData getData() {
return data;
}
public int getStatus() {
return status;
}
@Override
public String toString() {
return "ExecutionResults{" +
"data=" + getData() +
", status=" + getStatus() +
'}';
}
}
}
Служебный класс, который перенаправляет все выходные данные и содержимое ошибок в поток, чтобы их можно было перенаправить куда угодно, выглядит следующим образом:
Этот класс в основном заимствован из решения Перенаправить вывод консоли на строку в Java с некоторыми импровизациями.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
/**
* This class is an improvisation of the solution provided in https://stackru.com/a/30665299/679824
*/
public class ConsoleCapturer {
private ByteArrayOutputStream baosOutput, baosError;
private PrintStream previousOut, previousError;
private boolean capturing;
public void start() {
if (capturing) {
return;
}
capturing = true;
previousOut = System.out;
previousError = System.err;
baosOutput = new ByteArrayOutputStream();
baosError = new ByteArrayOutputStream();
System.setOut(new PrintStream(new OutputStreamCombiner(previousOut, baosOutput)));
System.setErr(new PrintStream(new OutputStreamCombiner(previousError, baosError)));
}
public CapturedData stop() {
if (!capturing) {
return new CapturedData();
}
System.setOut(previousOut);
System.setErr(previousError);
String output = baosOutput.toString();
String error = baosError.toString();
try {
baosOutput.close();
baosError.close();
} catch (IOException e) {
e.printStackTrace();
}
baosOutput = null;
previousOut = null;
capturing = false;
return new CapturedData(output, error);
}
private static class OutputStreamCombiner extends OutputStream {
private OutputStream[] outputStreams;
OutputStreamCombiner(OutputStream... outputStreams) {
this.outputStreams = outputStreams;
}
public void write(int b) throws IOException {
for (OutputStream os : outputStreams) {
os.write(b);
}
}
public void flush() throws IOException {
for (OutputStream os : outputStreams) {
os.flush();
}
}
public void close() throws IOException {
for (OutputStream os : outputStreams) {
os.close();
}
}
}
public static class CapturedData {
private String output;
private String error;
CapturedData() {
this("", "");
}
public CapturedData(String output, String error) {
this.output = output;
this.error = error;
}
public String getError() {
return error;
}
public String getOutput() {
return output;
}
@Override
public String toString() {
return "CapturedData{" +
"output='" + getOutput() + '\'' +
", error='" + getError() + '\'' +
'}';
}
}
}
Используемый тестовый класс выглядит следующим образом
import org.testng.annotations.Test;
public class SampleTestClass {
@Test
public void testMethod() {
System.err.println("This goes into the error console");
System.out.println("This goes into the console");
}
}
Выход выглядит как ниже
***Main Thread running in Thread [1]***
***Worker Thread running in Thread [11]***
This goes into the console
This goes into the error console
PASSED: testMethod
===============================================
Command line test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Command line suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
******Printing the TestNG output******
ExecutionResults{data=CapturedData{output='This goes into the console
PASSED: testMethod
===============================================
Command line test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Command line suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
', error='This goes into the error console
'}, status=0}
**************************************
Process finished with exit code 0