2014-12-10 2 views
2

У меня есть платформа автоматизации пользовательского интерфейса, которая запускает тесты с использованием TestNG и проходит через страницы с использованием Selenium/WebDriver. Зачастую страницы, которые я тестирую, вызывают вызовы AJAX, которые изменяют DOM при возврате. В этих случаях я использую Selenium явным ожиданиям, чтобы объявить условие DOM, которое я хочу выполнить, прежде чем автоматизация может продолжить (IE: некоторые кнопки активируются).Как определить, откуда происходят прерывания потока Java?

Метод FluentWait.until внутри селена обрабатывает это путем опроса DOM для моего ExpectedCondition каждые 500 мс и вызова Thread.sleep() между этими проверками.

Когда я запускаю два теста назад в комплекте TestNG, это отлично работает для первого теста, но начинает сбой прерываться с InterruptedException примерно на полпути через каждый последующий тест. Это непротиворечиво. Исключения выглядят так:

Associated Throwable Type: class org.openqa.selenium.WebDriverException Associated Throwable Message: java.lang.InterruptedException: sleep interrupted 

Странно, что здесь нет многопоточности. Я отключил Selenium Grid, прокси-сервер BrowserMob и все остальные части кода, которые могут быть конфликтующими. Я прочитал оба эти вопроса:

https://stackoverflow.com/questions/24495176/why-is-thread-sleep-being-interrupted - Закрыто для того, чтобы не предоставлять достаточно деталей, но в одном из предложенных ответов говорится, что для отладки метода Thread.interrupt следует отменить.

Who interrupts my thread? - В принятом ответе также говорится, что для отладки метода Thread.interrupt следует переопределить.

Моя проблема с этим решением заключается в том, что помещение точки останова в существующий метод Thread.interrupt не выявляет каких-либо вызовов в то время, когда поток прерывается. Сюда входят вызовы от всех моих зависимостей третьих лиц (IE: TestNG и Selenium). Все, что вызывает это прерывание потока, похоже, является внешним по отношению к моей структуре.

Я также попытался вызывать Thread.currentThread.isInterrupted() в каждой точке до вызова FluentWait.until и он последовательно возвращает false. Я даже использовал функцию оценки IntelliJ для проверки isInterrupted внутри самого кода Selenium. Этот поток прерывается только после вызова Thread.sleep внутри FluentWait.until.

Я видел, как это происходило на нескольких серверах сборки Windows, а также на моем Macbook, поэтому это не похоже на конкретную машину.

Я подумал, что это может быть вызвано таймаутом TestNG, но сокращение тайм-аута TestNG в моем наборе дало другое поведение, чем эти прерывания.

В настоящее время я работаю вокруг этого вопроса со следующим кодом, который проглотит исключение и возобновляет явное ожидание:

public static boolean waitForElementStatus(Stuff) 
{ 

    /* snip - setup for ExpectedCondition (change) */ 

    long startSeconds = new Date().getTime()/1000; 
    long currentSeconds = startSeconds; 
    long remainingSeconds = maxElementStatusChangeSeconds; 
    WebDriverWait waitForElement = new WebDriverWait(driver, maxElementStatusChangeSeconds); 
    boolean changed = false; 
    boolean firstWait = true; // If specified time is 0 we still want to check once. 
    out:while(firstWait || remainingSeconds > 0) 
    { 
    firstWait = false; 
    Boolean exceptionThrown = false; 
    try 
    { 
     waitForElement.until(change); 
    } 
    catch(Throwable t) 
    { 
     exceptionThrown = true; 
     if(t.getCause()) != null 
     { 
     t = t.getCause(); // InterruptedException is wrapped inside a WebDriverException 
     } 
     if(t.getClass().equals(InterruptedException.class)) 
     { 
     Thread.interrupted(); // clear interrupt status for this thread 
     currentSeconds = new Date().getTime()/1000; 
     remainingSeconds = startSeconds + maxElementStatusChangeSeconds - currentSeconds; 
     if(remainingSeconds > 0) 
     { 
      String warning = String.format("Caught unidentified interrupt inside Selenium " + 
      "FluentWait.until call. Swallowing interrupt and repeating call with [%s] seconds " + 
      "remaining.", remainingSeconds); 
      CombinedLogger.warn(warning); 
      waitForElement = new WebDriverWait(driver, remainingSeconds); 
     } 
     else 
     { 
      // If a timeout exception would have been thrown instead of the interruption then 
      // we'll allow the WebDriverWait to execute one last time so it can throw the 
      // timeout instead. 
      waitForElement = new WebDriverWait(driver, 0); 
     } 
     } 
     else if(haltOnFailure) // for any other exception type such as TimeoutException 
     { 
     CombinedLogger.error(stuff + "...FAILURE(HALTING)", t); 
     break out; 
     } 
     else // for any other exception type such as TimeoutException 
     { 
     CombinedLogger.info(stuff + "...failure(non-halting)"); 
     break out; 
     } 
    } 
    if(!exceptionThrown) 
    { 
     changed = true; 
     CombinedLogger.info(stuff + "...success "); 
     break out; 
    } 
    } 
    return changed; 
} 

Этот способ делает функцию, и, к счастью, эти загадочные прерывания происходят только спорадически после (они не повторяются повторно), поэтому тесты могут продолжаться. Однако я понимаю, что проглатывание InterruptedException - это плохая форма. Если возможно, я хотел бы определить, где и почему происходят эти прерывания, чтобы я мог положить им конец, а не использовать этот хак.

Простое распространение исключений не является вариантом, так как эти тесты должны продолжать работать, а не послушно сбой.

Существуют ли какие-либо известные утилиты, аргументы JVM или библиотеки, которые я мог бы использовать, которые помогли бы мне отслеживать прерывания потоков Java, вызванные кодом, который вышел из-под контроля?

Обновление 12/10/2014: Я захватил две свалки. Один из них находится непосредственно перед прерыванием, а один - сразу после него. Единственное различие между ними - номер строки прерванного потока (после прерывания происходит переход от блока try к блоку catch). Не уверен, что это говорит мне, но вот данные:

Full thread dump (immediately before interrupt) 
 

 
"[email protected]" prio=5 tid=0xc nid=NA runnable 
 
    java.lang.Thread.State: RUNNABLE 
 
\t at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:232) 
 
\t /* snip - company stuff */ 
 
\t at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1) 
 
\t at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
 
\t at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
 
\t at java.lang.reflect.Method.invoke(Method.java:606) 
 
\t at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84) 
 
\t at org.testng.internal.InvokeMethodRunnable.runOne(InvokeMethodRunnable.java:46) 
 
\t at org.testng.internal.InvokeMethodRunnable.run(InvokeMethodRunnable.java:37) 
 
\t at org.testng.internal.MethodInvocationHelper.invokeWithTimeoutWithNoExecutor(MethodInvocationHelper.java:240) 
 
\t at org.testng.internal.MethodInvocationHelper.invokeWithTimeout(MethodInvocationHelper.java:229) 
 
\t at org.testng.internal.Invoker.invokeMethod(Invoker.java:724) 
 
\t at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901) 
 
\t at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231) 
 
\t at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127) 
 
\t at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111) 
 
\t at org.testng.TestRunner.privateRun(TestRunner.java:767) 
 
\t at org.testng.TestRunner.run(TestRunner.java:617) 
 
\t at org.testng.SuiteRunner.runTest(SuiteRunner.java:348) 
 
\t at org.testng.SuiteRunner.access$000(SuiteRunner.java:38) 
 
\t at org.testng.SuiteRunner$SuiteWorker.run(SuiteRunner.java:382) 
 
\t at org.testng.internal.thread.ThreadUtil$2.call(ThreadUtil.java:64) 
 
\t at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
 
\t at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
 
\t at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
 
\t at java.lang.Thread.run(Thread.java:745) 
 

 
"[email protected]" prio=5 tid=0x1 nid=NA waiting 
 
    java.lang.Thread.State: WAITING 
 
\t at sun.misc.Unsafe.park(Unsafe.java:-1) 
 
\t at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226) 
 
\t at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:422) 
 
\t at java.util.concurrent.FutureTask.get(FutureTask.java:199) 
 
\t at java.util.concurrent.AbstractExecutorService.invokeAll(AbstractExecutorService.java:289) 
 
\t at org.testng.internal.thread.ThreadUtil.execute(ThreadUtil.java:72) 
 
\t at org.testng.SuiteRunner.runInParallelTestMode(SuiteRunner.java:367) 
 
\t at org.testng.SuiteRunner.privateRun(SuiteRunner.java:308) 
 
\t at org.testng.SuiteRunner.run(SuiteRunner.java:254) 
 
\t at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) 
 
\t at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) 
 
\t at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224) 
 
\t at org.testng.TestNG.runSuitesLocally(TestNG.java:1149) 
 
\t at org.testng.TestNG.run(TestNG.java:1057) 
 
\t at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111) 
 
\t at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204) 
 
\t at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175) 
 
\t at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:125) 
 

 
"[email protected]" daemon prio=5 tid=0x15 nid=NA runnable 
 
    java.lang.Thread.State: RUNNABLE 
 
\t at java.io.FileInputStream.readBytes(FileInputStream.java:-1) 
 
\t at java.io.FileInputStream.read(FileInputStream.java:272) 
 
\t at java.io.BufferedInputStream.fill(BufferedInputStream.java:235) 
 
\t at java.io.BufferedInputStream.read1(BufferedInputStream.java:275) 
 
\t at java.io.BufferedInputStream.read(BufferedInputStream.java:334) 
 
\t - locked <0xe08> (a java.lang.UNIXProcess$ProcessPipeInputStream) 
 
\t at java.io.FilterInputStream.read(FilterInputStream.java:107) 
 
\t at org.apache.commons.exec.StreamPumper.run(StreamPumper.java:105) 
 
\t at java.lang.Thread.run(Thread.java:745) 
 

 
"[email protected]" daemon prio=5 tid=0x14 nid=NA runnable 
 
    java.lang.Thread.State: RUNNABLE 
 
\t at java.io.FileInputStream.readBytes(FileInputStream.java:-1) 
 
\t at java.io.FileInputStream.read(FileInputStream.java:272) 
 
\t at java.io.BufferedInputStream.fill(BufferedInputStream.java:235) 
 
\t at java.io.BufferedInputStream.read1(BufferedInputStream.java:275) 
 
\t at java.io.BufferedInputStream.read(BufferedInputStream.java:334) 
 
\t - locked <0xe09> (a java.lang.UNIXProcess$ProcessPipeInputStream) 
 
\t at java.io.FilterInputStream.read(FilterInputStream.java:107) 
 
\t at org.apache.commons.exec.StreamPumper.run(StreamPumper.java:105) 
 
\t at java.lang.Thread.run(Thread.java:745) 
 

 
"[email protected]" prio=5 tid=0x13 nid=NA waiting 
 
    java.lang.Thread.State: WAITING 
 
\t at java.lang.Object.wait(Object.java:-1) 
 
\t at java.lang.Object.wait(Object.java:503) 
 
\t at java.lang.UNIXProcess.waitFor(UNIXProcess.java:261) 
 
\t at org.apache.commons.exec.DefaultExecutor.executeInternal(DefaultExecutor.java:347) 
 
\t at org.apache.commons.exec.DefaultExecutor.access$200(DefaultExecutor.java:46) 
 
\t at org.apache.commons.exec.DefaultExecutor$1.run(DefaultExecutor.java:188) 
 

 
"process [email protected]" daemon prio=10 tid=0x10 nid=NA runnable 
 
    java.lang.Thread.State: RUNNABLE 
 
\t at java.lang.UNIXProcess.waitForProcessExit(UNIXProcess.java:-1) 
 
\t at java.lang.UNIXProcess.access$500(UNIXProcess.java:54) 
 
\t at java.lang.UNIXProcess$4.run(UNIXProcess.java:225) 
 
\t at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
 
\t at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
 
\t at java.lang.Thread.run(Thread.java:745) 
 

 
"[email protected]" prio=5 tid=0xb nid=NA runnable 
 
    java.lang.Thread.State: RUNNABLE 
 
\t at java.net.SocketInputStream.socketRead0(SocketInputStream.java:-1) 
 
\t at java.net.SocketInputStream.read(SocketInputStream.java:152) 
 
\t at java.net.SocketInputStream.read(SocketInputStream.java:122) 
 
\t at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283) 
 
\t at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325) 
 
\t at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177) 
 
\t - locked <0xe0b> (a java.io.InputStreamReader) 
 
\t at java.io.InputStreamReader.read(InputStreamReader.java:184) 
 
\t at java.io.BufferedReader.fill(BufferedReader.java:154) 
 
\t at java.io.BufferedReader.readLine(BufferedReader.java:317) 
 
\t at java.io.BufferedReader.readLine(BufferedReader.java:382) 
 
\t at org.testng.remote.strprotocol.BaseMessageSender$ReaderThread.run(BaseMessageSender.java:245) 
 

 
"[email protected]" daemon prio=8 tid=0x3 nid=NA waiting 
 
    java.lang.Thread.State: WAITING 
 
\t at java.lang.Object.wait(Object.java:-1) 
 
\t at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) 
 
\t at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151) 
 
\t at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:189) 
 

 
"Reference [email protected]" daemon prio=10 tid=0x2 nid=NA waiting 
 
    java.lang.Thread.State: WAITING 
 
\t at java.lang.Object.wait(Object.java:-1) 
 
\t at java.lang.Object.wait(Object.java:503) 
 
\t at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133) 
 

 
"Signal [email protected]" daemon prio=9 tid=0x4 nid=NA runnable 
 
    java.lang.Thread.State: RUNNABLE

+0

«Странно, что здесь нет многопоточности». Хорошо ясно, что это не так, потому что ваш сон прерывается. Ваш первый шаг должен состоять в том, чтобы попытаться изолировать ваш код и воспроизвести его с максимально возможным количеством движущихся частей. Прежде всего, если вы напишете простой метод 'main()', который вызывает ваши методы '@ Test' напрямую (минуя TestNG), вы все равно будете прерваны? – dimo414

+0

Это справедливая точка. Там всегда происходит некоторая степень многопоточности. Изоляция этого отказа, вероятно, займет у меня несколько дней. Я посмотрю, смогу ли я это сделать в ближайшее время. –

ответ

0

Существует не так много, что можно сделать вывод из дампа потока, как и в чем это вызвано. Но на самом деле вы не можете слишком сильно полагаться на Thread.sleep(), это может быть прервано по известной/неизвестной причине. Возможно, причина в последнем случае.

Thread.sleep() является одним из немногих методов, который серьезно относится к прерыванию. Поскольку поток не может обрабатывать InterruptedException, пока он спит, вам нужно обработать его.

То, что вы делаете прямо сейчас, может быть не обходным путем, а выходом в таких случаях, где мы не можем обойтись без Thread.sleep().

+0

Мои варианты были: # 1 -Это обходной путь (уже на месте). # 2 - Прекратите мои назначенные задачи, чтобы преследовать загадочные прерывания без надлежащих инструментов или ведения журнала, чтобы определить, почему они происходят ...Неудивительно, что я выбрал №1. –

0

Немного устарел, но у меня есть аналогичная проблема и с помощью вашей ранее размещенной ссылки (https://stackoverflow.com/a/2476246) Я поставил точку останова в метод Thread.interrupt().

Он показывает, что прерывание было выполнено с помощью метода StoryManager.waitUntilAllDoneOrFailed(), который запускает метод future.cancel() после таймаута, установленного для всей истории.

Вся моя установка:

page.getPageObject().withTimeoutOf(convertDuration(duration)).waitFor(by); 

где продолжительность составляет около 60 секунд. (Минута из-за какие-то асинхронные вещи)

и

configuredEmbedder().embedderControls().useStoryTimeouts("30"); 

И StackTrace является:

at java.util.concurrent.FutureTask.cancel(FutureTask.java:174) 
     at org.jbehave.core.embedder.StoryManager.waitUntilAllDoneOrFailed(StoryManager.java:184) 
     at org.jbehave.core.embedder.StoryManager.performStories(StoryManager.java:121) 
     at org.jbehave.core.embedder.StoryManager.runStories(StoryManager.java:107) 

и прерывает метод позже Thread.sleep() в ThucydidesFluentWait.doWait() (в основном в нижнем экземпляре Метод сна сна())

Увеличение таймаута истории или правильная настройка waitFor (...) timeout против тайм-аута истории решает проблему на моей стороне.

Смежные вопросы