Nagios集成Selenium步骤:
- 编写一个用来调用测试用例的Java Main函数
- 编写运行测试用例的shell脚本check_selenium.sh
- 定义Nagios Command和Service
Java测试程序
说明:Java Main函数使用了https://github.com/czunker/check_selenium 的CallSeleniumTest类,略作修改。
POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.itrunner</groupId>
<artifactId>nagios-selenium</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<project.encoding>UTF-8</project.encoding>
<jdk.version>1.8</jdk.version>
<selenium.version>3.14.0</selenium.version>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<encoding>${project.encoding}</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<encoding>${project.encoding}</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<mainClass>org.itrunner.tests.CallSeleniumTest</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptors>
<descriptor>src/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.5.0.1254</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-support</artifactId>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>com.codeborne</groupId>
<artifactId>phantomjsdriver</artifactId>
<version>1.4.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>
CallSeleniumTest
package org.itrunner.tests;
import org.apache.commons.cli.*;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.firefox.NotConnectedException;
public class CallSeleniumTest {
private static int timeout = 30;
private static final int NAGIOS_OK = 0;
private static final int NAGIOS_WARNING = 1;
private static final int NAGIOS_CRITICAL = 2;
private static final int NAGIOS_UNKNOWN = 3;
private static final String NAGIOS_TEXT_OK = "OK";
private static final String NAGIOS_TEXT_WARNING = "WARNING";
private static final String NAGIOS_TEXT_CRITICAL = "CRITICAL";
private static final String NAGIOS_TEXT_UNKNOWN = "UNKNOWN";
private Options options = null;
private TestResult runTest(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class<TestBase> seleniumTestClass = (Class<TestBase>) Class.forName(className);
return seleniumTestClass.newInstance().run();
}
public static void main(String[] args) throws Exception {
CallSeleniumTest seTest = new CallSeleniumTest();
Option optionClass = new Option("c", "class", true, "full classname of test case (required) e.g. \"org.itrunner.tests.hosts.Baidu\"");
Option optionTimeout = new Option("t", "timeout", true, "timeout, default is 30");
Option optionVerbose = new Option("v", "verbose", false, "show a lot of information (useful in case of problems)");
Option optionHelp = new Option("h", "help", false, "show this help screen");
seTest.options = new Options();
seTest.options.addOption(optionClass);
seTest.options.addOption(optionTimeout);
seTest.options.addOption(optionVerbose);
seTest.options.addOption(optionHelp);
CommandLineParser parser = new DefaultParser();
CommandLine cmd = null;
String output = seTest.NAGIOS_TEXT_UNKNOWN + " - Upps";
int nagios = seTest.NAGIOS_UNKNOWN;
try {
cmd = parser.parse(seTest.options, args);
// has to be checked manually, otherwise you can‘t access the help message without specifying correct parameters
if (cmd.hasOption("h") || !cmd.hasOption("c")) {
usage(seTest.options);
System.exit(nagios); //NOSONAR
}
if (cmd.hasOption("t")) {
timeout = Integer.parseInt(cmd.getOptionValue("t"));
}
TestResult result = seTest.runTest(cmd.getOptionValue("c"));
output = seTest.NAGIOS_TEXT_OK + " - " + cmd.getOptionValue("c") + " Tests passed - " + result.toString();
nagios = seTest.NAGIOS_OK;
} catch (ParseException e) {
output = seTest.NAGIOS_TEXT_UNKNOWN + " - Parameter problems: " + e.getMessage();
nagios = seTest.NAGIOS_UNKNOWN;
usage(seTest.options);
} catch (ClassNotFoundException e) {
output = seTest.NAGIOS_TEXT_UNKNOWN + " - Test case class: " + e.getMessage() + " not found!";
nagios = seTest.NAGIOS_UNKNOWN;
} catch (TimeoutException | CriticalException e) {
output = seTest.NAGIOS_TEXT_CRITICAL + " - Test Failures: " + e.getMessage();
nagios = seTest.NAGIOS_CRITICAL;
} catch (Exception e) {
output = seTest.NAGIOS_TEXT_WARNING + " - Test Failures: " + processException(cmd, e);
nagios = seTest.NAGIOS_WARNING;
} finally {
println(output);
System.exit(nagios); //NOSONAR
}
}
private static String processException(CommandLine cmd, Exception e) {
if (cmd.hasOption("v")) {
e.printStackTrace(); //NOSONAR
}
if (isCausedBy(e, NotConnectedException.class)) {
return "Failed to connect to binary FirefoxBinary";
}
return e.getMessage();
}
private static void usage(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("check_selenium", options);
println("This version of check_selenium was tested with:");
println(" - selenium 3.14.0");
println(" - selenium ide 3.3.1");
println(" - test case exported as Java / JUnit 4 / WebDriver");
println("Some example calls:");
println(" ./check_selenium.sh -c \"org.itrunner.tests.hosts.Baidu\"");
println(" ./check_selenium.sh --class \"org.itrunner.tests.hosts.Baidu\"");
}
public static int getTimeout() {
return timeout;
}
private static void println(String x) {
System.out.println(x); //NOSONAR
}
private static <T extends Throwable> boolean isCausedBy(final Throwable exception, Class<T> clazz) {
Throwable cause = exception;
while (cause != null) {
if (clazz.isInstance(cause)) {
return true;
}
cause = cause.getCause();
}
return false;
}
}
check_selenium.sh
#!/bin/bash
export DISPLAY=:1
#xhost +
JAVA_HOME=/opt/java/jdk1.8.0_77
$JAVA_HOME/bin/java -jar $(dirname $0)/lib/nagios-selenium-1.0.jar $@
Assembly
<assembly>
<id>bin</id>
<formats>
<!--<format>zip</format>-->
<format>dir</format>
</formats>
<baseDirectory>libexec</baseDirectory>
<dependencySets>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>src/main/resources</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>check_selenium.sh</include>
</includes>
</fileSet>
<fileSet>
<directory>src/main/resources</directory>
<outputDirectory>lib</outputDirectory>
<includes>
<include>config.ini</include>
</includes>
</fileSet>
</fileSets>
</assembly>
打包后的结构如下:
部署时将libexec目录下的内容拷贝到nagios/libexec目录即可。
测试用例
DriverFactory
package org.itrunner.tests;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxDriverLogLevel;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.util.ArrayList;
import java.util.List;
import static org.itrunner.tests.utils.Config.CONFIG;
import static org.openqa.selenium.phantomjs.PhantomJSDriverService.*;
public class DriverFactory {
public static RemoteWebDriver createDriver() {
if (CONFIG.getDriverType().equals("firefox")) {
return createFirefoxDriver();
}
return createPhantomJSDriver();
}
public static RemoteWebDriver createPhantomJSDriver() {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setJavascriptEnabled(true);
capabilities.setCapability(PHANTOMJS_EXECUTABLE_PATH_PROPERTY, CONFIG.getPhantomJsBinaryPath());
List<String> cliArgs = new ArrayList<>();
cliArgs.add("--web-security=false");
cliArgs.add("--ssl-protocol=any");
cliArgs.add("--ignore-ssl-errors=true");
capabilities.setCapability(PHANTOMJS_CLI_ARGS, cliArgs);
// Control LogLevel for GhostDriver, via CLI arguments
String[] ghostDriverCliArgs = {"--logLevel=" + CONFIG.getLogLevel()};
capabilities.setCapability(PHANTOMJS_GHOSTDRIVER_CLI_ARGS, ghostDriverCliArgs);
if (hasProxy()) {
capabilities.setCapability("proxy", getProxy());
}
return new PhantomJSDriver(capabilities);
}
public static RemoteWebDriver createFirefoxDriver() {
System.setProperty("webdriver.gecko.driver", CONFIG.getGeckoDriver());
FirefoxOptions options = new FirefoxOptions();
options.setLogLevel(FirefoxDriverLogLevel.fromString(CONFIG.getLogLevel()));
if (hasProxy()) {
options.setProxy(getProxy());
}
RemoteWebDriver driver = new FirefoxDriver(options);
driver.manage().window().maximize();
return driver;
}
private static Proxy getProxy() {
Proxy proxy = new Proxy();
proxy.setHttpProxy(CONFIG.getProxyHost());
return proxy;
}
private static boolean hasProxy() {
return CONFIG.getProxyHost() != null && !CONFIG.getProxyHost().equals("");
}
}
示例使用了FirefoxDriver和PhantomJSDriver。Selenium 3使用FirefoxDriver时,系统除需安装firefox和图形界面外,还需要下载geckodriver,配置系统属性“webdriver.gecko.driver”。使用PhantomJSDriver时,需下载PhantomJS,配置“phantomjs.binary.path”。PhantomJSDriver无需图形界面,性能更高,更适合与nagios集成。
TestBase
package org.itrunner.tests;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
import static java.lang.System.currentTimeMillis;
import static org.openqa.selenium.OutputType.BYTES;
import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;
public abstract class TestBase {
protected RemoteWebDriver driver;
private long startTime;
protected TestResult result = new TestResult();
@Before
public void setup() {
startTime = currentTimeMillis();
nextStep(() -> createDriver(), "init");
setTimeout();
setStopAtShutdown();
}
public TestResult run() {
setup();
test();
tearDown();
setTotalTime();
return result;
}
@After
public void tearDown() {
nextStep(() -> driver.quit(), "destroy");
}
private void createDriver() {
driver = DriverFactory.createDriver();
}
public abstract void test();
protected void savePageSource(String host) {
try {
File sourceFile = new File("reports/" + host + ".html");
FileUtils.writeStringToFile(sourceFile, driver.getPageSource(), Charset.defaultCharset());
} catch (IOException e) { //NOSONAR
// do nothing
}
}
protected void takeScreenshot(String host) {
File imageFile = new File("reports/" + host + ".png");
try {
FileUtils.writeByteArrayToFile(imageFile, driver.getScreenshotAs(BYTES));
} catch (IOException e) { //NOSONAR
// do nothing
}
}
protected void nextStep(TestStep step, String stepName) {
long beginTime = currentTimeMillis();
try {
step.run();
} catch (TimeoutException | NoSuchElementException e) {
throw new CriticalException(stepName + " failed: " + e.getMessage(), e);
}
result.putStepTime(stepName, currentTimeMillis() - beginTime);
}
public boolean isElementPresent(By by) {
try {
return waitForElementPresent(by);
} catch (TimeoutException e) { //NOSONAR
return false;
}
}
public void open(final String url) {
nextStep(() -> {
driver.get(url);
}, "loading page");
}
public void click(final By by, String stepName) {
nextStep(() -> driver.findElement(by).click(), stepName);
}
public void waitForTitlePresent(final String title) {
nextStep(() -> waitForCondition(titleIs(title)), "finding title");
}
private boolean waitForElementPresent(By by) {
return waitForCondition(visibilityOfElementLocated(by)).isDisplayed();
}
private <T> T waitForCondition(ExpectedCondition<T> condition) {
return (new WebDriverWait(driver, CallSeleniumTest.getTimeout())).until(condition);
}
private void setTimeout() {
driver.manage().timeouts().implicitlyWait(CallSeleniumTest.getTimeout(), TimeUnit.SECONDS);
}
private void setStopAtShutdown() {
Runtime.getRuntime().addShutdownHook(new Thread("Selenium Quit Hook") {
@Override
public void run() {
driver.quit();
}
});
}
private void setTotalTime() {
result.setTotalTime(currentTimeMillis() - startTime);
}
}
示例代码记录了每步执行的时间。
网站测试
package org.itrunner.tests.hosts;
import org.itrunner.tests.TestBase;
import org.junit.Test;
import org.openqa.selenium.By;
import static org.itrunner.tests.utils.Config.CONFIG;
public class Baidu extends TestBase {
@Override
@Test
public void test() {
open(CONFIG.getBaiduUrl());
waitForTitlePresent("百度一下,你就知道");
nextStep(() -> {
driver.findElement(By.linkText("登录")).click();
driver.findElementById("TANGRAM__PSP_10__footerULoginBtn").click();
driver.findElementById("TANGRAM__PSP_10__userName").sendKeys(CONFIG.getBaiduUsername());
driver.findElementById("TANGRAM__PSP_10__password").sendKeys(CONFIG.getBaiduPassword());
driver.findElementById("TANGRAM__PSP_10__submit").click();
takeScreenshot("baidu");
}, "login");
}
}
配置Command和Service
Command
define command {
command_name check_selenium
command_line $USER1$/check_selenium.sh -c $ARG1$
}
Service
define service {
service_description selenium_baidu
use service-check-05min
host_name www.baidu.com
check_command check_selenium!org.itrunner.tests.hosts.Baidu
}
常见问题
-
Error: Package: perl-Net-SNMP-6.0.1-7.el7.noarch (epel) Requires: perl(Crypt::DES)
在RHEL 7安装perl-Net-SNMP时,报这个错误,请先到rpmfind下载安装perl-Crypt-DES-2.05-20.el7.x86_64.rpm -
How to confirm the param "DISPLAY"?
Log into the graphical interface:
echo $DISPLAY -
CHECK_NRPE: Received 0 bytes from daemon. Check the remote server logs for error messages
Install nrpe:
./configure --enable-command-args -
NRPE installation error: configure: error: Cannot find ssl headers
yum install openssl-devel - (Service check timed out after 60.01 seconds)
在nagios.cfg配置中service_check_timeout=60,如果页面检查超时,nagios将停止检查,根据实际情况调整参数
参考资料
Nagios - The Industry Standard In IT Infrastructure Monitoring
Nagios Core
Nagios Core Quickstart Installation Guides
Nagios NRPE Documentation
Zabbix - The Enterprise-Class Open Source Network Monitoring Solution
SeleniumHQ
geckodriver
PhantomJS