当PhantomJS搜索空闲端口时,如何排除端口范围?

时间:2017-01-25 11:10:29

标签: java selenium phantomjs cucumber serenity-bdd

我正在使用Serenity BDDPhantomJS驱动程序进行网络测试。

TL; DR
有时PhantomJSDriverService会尝试在已占用的端口上初始化,但我得到异常Could not instantiate class org.openqa.selenium.phantomjs.PhantomJSDriver。问题是 - 如何限制phantomjs扫描的端口范围,以免发生这种情况?

详情
我们项目中的Webtests通常会成功。有时(可能大约1个20的构建)它们绝对随机地失败 - 例如代码没有变化,它们失败了,然后在重新运行后(每2小时)恢复一次。

下面是典型故障的堆栈跟踪(包名和类名已更改):

Running com.package.LogIntoEnduserPortalFailTest
19:21:24,186  INFO Serenity:222 - Test Suite Started: Log into enduser portal failed
19:21:24,188  INFO Serenity:232 - 
 _____ _____ ____ _____   ____ _____  _    ____ _____ _____ ____  
|_   _| ____/ ___|_   _| / ___|_   _|/ \  |  _ \_   _| ____|  _ \ 
  | | |  _| \___ \ | |   \___ \ | | / _ \ | |_) || | |  _| | | | |
  | | | |___ ___) || |    ___) || |/ ___ \|  _ < | | | |___| |_| |
  |_| |_____|____/ |_|   |____/ |_/_/   \_\_| \_\|_| |_____|____/ 


TEST STARTED: I am logging into Enduser portal. I use wrong credentials. Login page with "Authentication failed (ERR0122)" error should be displayed

-------------------------------------------------------------------
19:21:24,244  INFO WebDriverFactory:218 - PhantomJS not on path, trying to get path from PHANTOMJS_BINARY_PATH
19:21:24,245  INFO WebDriverFactory:221 - PHANTOMJS_BINARY_PATH = null
19:21:24,245  INFO WebDriverFactory:222 - PHANTOMJS_EXECUTABLE_PATH_PROPERTY = /users/tmx1221/user1/g_bsp/phantomjs/phantomjs
Dec 12, 2016 7:21:24 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: executable: /users/tmx1221/user1/g_bsp/phantomjs/phantomjs
Dec 12, 2016 7:21:24 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: port: 22447
Dec 12, 2016 7:21:24 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: arguments: [--web-security=false, --ignore-ssl-errors=true, --webdriver-loglevel=OFF, --ssl-protocol=any, --webdriver=22447, --webdriver-logfile=/path/to/phantomjsdriver.log]
Dec 12, 2016 7:21:24 PM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: environment: {}
PhantomJS is launching GhostDriver...
Dec 12, 2016 7:21:44 PM org.openqa.selenium.os.UnixProcess checkForError
SEVERE: org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
19:21:44,258 ERROR WebDriverFacade:143 - FAILED TO CREATE NEW WEBDRIVER_DRIVER INSTANCE class org.openqa.selenium.phantomjs.PhantomJSDriver: Could not instantiate class org.openqa.selenium.phantomjs.PhantomJSDriver
net.thucydides.core.webdriver.UnsupportedDriverException: Could not instantiate class org.openqa.selenium.phantomjs.PhantomJSDriver
    at net.thucydides.core.webdriver.WebDriverFactory.newWebdriverInstance(WebDriverFactory.java:209)
    at net.thucydides.core.webdriver.WebDriverFacade.newDriverInstance(WebDriverFacade.java:140)
    at net.thucydides.core.webdriver.WebDriverFacade.newProxyDriver(WebDriverFacade.java:131)
    at net.thucydides.core.webdriver.WebDriverFacade.getProxiedDriver(WebDriverFacade.java:103)
    at net.thucydides.core.webdriver.WebDriverFacade.openIgnoringHtmlUnitScriptErrors(WebDriverFacade.java:176)
    at net.thucydides.core.webdriver.WebDriverFacade.get(WebDriverFacade.java:171)
    at net.serenitybdd.core.pages.PageObject.openPageAtUrl(PageObject.java:828)
    at net.serenitybdd.core.pages.PageObject.open(PageObject.java:738)
    at net.serenitybdd.core.pages.PageObject.open(PageObject.java:726)
    at com.package.EnduserLoginSteps.openEnduserPortalLoginPage(EnduserLoginSteps.java:66)
    at com.package.EnduserLoginSteps$$EnhancerByCGLIB$$3575db30.CGLIB$openEnduserPortalLoginPage$0(<generated>)
    at com.package.EnduserLoginSteps$$EnhancerByCGLIB$$3575db30$$FastClassByCGLIB$$84ffb12e.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at net.thucydides.core.steps.StepInterceptor.invokeMethod(StepInterceptor.java:369)
    at net.thucydides.core.steps.StepInterceptor.executeTestStepMethod(StepInterceptor.java:354)
    at net.thucydides.core.steps.StepInterceptor.runTestStep(StepInterceptor.java:329)
    at net.thucydides.core.steps.StepInterceptor.testStepResult(StepInterceptor.java:134)
    at net.thucydides.core.steps.StepInterceptor.intercept(StepInterceptor.java:61)
    at com.package.EnduserLoginSteps$$EnhancerByCGLIB$$3575db30.openEnduserPortalLoginPage(<generated>)
    at com.package.LogIntoEnduserPortalFailStepDefinitions.openEnduserPortalLoginPage(LogIntoEnduserPortalFailStepDefinitions.java:58)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at cucumber.runtime.Utils$1.call(Utils.java:37)
    at cucumber.runtime.Timeout.timeout(Timeout.java:13)
    at cucumber.runtime.Utils.invoke(Utils.java:31)
    at cucumber.runtime.java.JavaStepDefinition.execute(JavaStepDefinition.java:38)
    at cucumber.runtime.StepDefinitionMatch.runStep(StepDefinitionMatch.java:37)
    at cucumber.runtime.Runtime.runStep(Runtime.java:299)
    at cucumber.runtime.model.StepContainer.runStep(StepContainer.java:44)
    at cucumber.runtime.model.StepContainer.runSteps(StepContainer.java:39)
    at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:44)
    at cucumber.runtime.junit.ExecutionUnitRunner.run(ExecutionUnitRunner.java:91)
    at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:63)
    at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:18)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at cucumber.runtime.junit.FeatureRunner.run(FeatureRunner.java:70)
    at cucumber.api.junit.Cucumber.runChild(Cucumber.java:93)
    at cucumber.api.junit.Cucumber.runChild(Cucumber.java:37)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at cucumber.api.junit.Cucumber.run(Cucumber.java:98)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:344)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:269)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:240)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:184)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:286)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:240)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121)
Caused by: org.openqa.selenium.remote.UnreachableBrowserException: Could not start a new session. Possible causes are invalid address of the remote server or browser start-up failure.
Build info: version: '2.53.0', revision: '35ae25b1534ae328c771e0856c93e187490ca824', time: '2016-03-15 10:43:46'
System info: host: 'tmx1221', ip: '10.1.209.126', os.name: 'Linux', os.arch: 'amd64', os.version: '3.0.101-68-default', java.version: '1.8.0_102'
Driver info: driver.version: PhantomJSDriver
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:665)
    at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:249)
    at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:131)
    at org.openqa.selenium.remote.RemoteWebDriver.<init>(RemoteWebDriver.java:144)
    at org.openqa.selenium.phantomjs.PhantomJSDriver.<init>(PhantomJSDriver.java:115)
    at org.openqa.selenium.phantomjs.PhantomJSDriver.<init>(PhantomJSDriver.java:104)
    at net.thucydides.core.webdriver.WebdriverInstanceFactory.newPhantomDriver(WebdriverInstanceFactory.java:150)
    at net.thucydides.core.webdriver.WebDriverFactory.phantomJSDriver(WebDriverFactory.java:497)
    at net.thucydides.core.webdriver.WebDriverFactory.newWebdriverInstance(WebDriverFactory.java:182)
    ... 58 more
Caused by: org.openqa.selenium.WebDriverException: Timed out waiting for driver server to start.
Build info: version: '2.53.0', revision: '35ae25b1534ae328c771e0856c93e187490ca824', time: '2016-03-15 10:43:46'
System info: host: 'tmx1221', ip: '10.1.209.126', os.name: 'Linux', os.arch: 'amd64', os.version: '3.0.101-68-default', java.version: '1.8.0_102'
Driver info: driver.version: PhantomJSDriver
    at org.openqa.selenium.remote.service.DriverService.waitUntilAvailable(DriverService.java:178)
    at org.openqa.selenium.remote.service.DriverService.start(DriverService.java:166)
    at org.openqa.selenium.phantomjs.PhantomJSCommandExecutor.execute(PhantomJSCommandExecutor.java:78)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:644)
    ... 66 more
Caused by: org.openqa.selenium.net.UrlChecker$TimeoutException: Timed out waiting for [http://localhost:22447/status] to be available after 20001 ms
    at org.openqa.selenium.net.UrlChecker.waitUntilAvailable(UrlChecker.java:107)
    at org.openqa.selenium.remote.service.DriverService.waitUntilAvailable(DriverService.java:175)
    ... 69 more
Caused by: com.google.common.util.concurrent.UncheckedTimeoutException: java.util.concurrent.TimeoutException
    at com.google.common.util.concurrent.SimpleTimeLimiter.callWithTimeout(SimpleTimeLimiter.java:143)
    at org.openqa.selenium.net.UrlChecker.waitUntilAvailable(UrlChecker.java:80)
    ... 70 more
Caused by: java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask.get(FutureTask.java:205)
    at com.google.common.util.concurrent.SimpleTimeLimiter.callWithTimeout(SimpleTimeLimiter.java:130)
    ... 71 more
19:21:44,336 ERROR Serenity:290 - 
           __  _____ _____ ____ _____   _____ _    ___ _     _____ ____  
  _       / / |_   _| ____/ ___|_   _| |  ___/ \  |_ _| |   | ____|  _ \ 
 (_)_____| |    | | |  _| \___ \ | |   | |_ / _ \  | || |   |  _| | | | |
  _|_____| |    | | | |___ ___) || |   |  _/ ___ \ | || |___| |___| |_| |
 (_)     | |    |_| |_____|____/ |_|   |_|/_/   \_\___|_____|_____|____/ 
          \_\                                                            

TEST FAILED WITH ERROR: I am logging into Enduser portal. I use wrong credentials. Login page with "Authentication failed (ERR0122)" error should be displayed
---------------------------------------------------------------------
19:21:44,638 ERROR Serenity:325 - TEST FAILED AT STEP Open enduser portal login page: instance, web-tests-session-id, 100
19:21:44,639 ERROR Serenity:327 - Could not instantiate class org.openqa.selenium.phantomjs.PhantomJSDriver

所以我注意到了行INFO: port: 22447,那时我才知道PhantomJSDriverService每次都在不同的端口上初始化。我开始检查失败的测试,结果发现所有失败的尝试都有端口224**225**,特别是:225472244722499

所以我在运行webtests的服务器上检查了这些端口:

user@host ~ $> netstat -tulpn | grep 22547
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 10.1.209.126:22547      :::*                    LISTEN      30525/java
user@host ~ $> netstat -tulpn | grep 22447
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 10.1.209.126:22447      :::*                    LISTEN      24367/java

......并且看到这些端口确实被占用了。不知道这些信息是否相关,但它们被JBoss实例占用(参见-Djboss.socket.binding.port-offset=22500):

user@host ~ $> ps aux | grep 30525
user    21921  0.0  0.0   5732   788 pts/2    S+   10:54   0:00 grep 30525
user    30525  7.1  4.0 3523364 1997072 ?     Sl   Jan24  74:06 /usr/lib64/jvm/java-1.7.0/bin/java -D[Standalone] -XX:+UseCompressedOops -server -Xss2048k -Xmx2G -Xms1G -XX:CMSInitiatingOccupancyFraction=85 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:NewSize=512m -XX:PermSize=512m -XX:MaxPermSize=512m -XX:+UseCompressedOops -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/log -XX:+PrintFlagsFinal -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled -XX:+DisableExplicitGC -verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:/path/to/log/gc.log.170124173856 -Dserver.home=/path/to/server -Dgatein.deploy.dir=/path/to/gatein -Dgatein.extensions.dir=/path/to/extensions -Djboss.as.management.blocking.timeout=600 -Djboss.bind.address=tmx1221 -Djboss.bind.address.management=tmx1221 -Dfile.encoding=ISO-8859-1 -Duser.timezone=CET -Dhttp.timeout=600000 -Djboss.bind.alias=1 -Dhttps.protocols=TLSv1 -Dinvariant.home=/path/to/InvariantData -Djavamelody.no-database=true -Djavamelody.system-actions-enabled=false -Djava.awt.headless=true -Dsun.lang.ClassLoader.allowArraySyntax=true -Djava.rmi.server.hostname=tmx1221 -Dhttp.timeout=600000  -Dorg.jboss.boot.log.file=/path/to/log/server.log -Dlogging.configuration=file:/path/to/configuration/logging.properties -jar /appl/local/jboss/jboss-epp-6.2.2/jboss-modules.jar -mp /users/tmx1221/user1/g_bsp/builds/jboss6-wft-2/server/wft/modules -jaxpmodule javax.xml.jaxp-provider org.jboss.as.standalone -Djboss.home.dir=/appl/local/jboss/jboss-epp-6.2.2 -Djboss.server.base.dir=/path/to/server/wft -c standalone.xml -Djboss.node.name=wft -Djboss.server.name=wft -Dorg.apache.commons.logging.diagnostics.dest=STDOUT -Djboss.socket.binding.port-offset=22500

所以看起来phantomjs检查此端口是否空闲返回不正确的结果,后来的PhantomJSDriverService无法实例化。

我想到了解决这个问题的3种方法:

  1. 为PhantomJSDriverService指定一个端口,以便它不会被随机拾取。我检查了Serenity的文档,我发现指定端口的唯一方法(phantomjs.webdriver.port)与webdriver.remote.url一起使用,但我们不会远程运行它们。
  2. 让Serenity重新运行失败的测试。根据文档,它是通过设置junit.retry.tests=true来完成的。但我们使用Cucumber来运行测试:@RunWith(CucumberWithSerenity.class),因此它对我不起作用。
  3. 限制由PhantomJSDriverService检查的端口的可能范围。我没有找到任何可能的解决方案。
  4. 配置参数-Dphantomjs.binary.path=/path/to/phantomjs
     -Dwebdriver.base.url=http://localhost:20180作为环境变量和

    webdriver.driver=phantomjs
    serenity.take.screenshots=AFTER_EACH_STEP
    

    作为serenity.properties档案中的参数。

    我非常感谢有关可能的解决方案的任何帮助。

0 个答案:

没有答案