需求:
在进行Nginx测试的过程中,经常需要对远程服务器执行一些shell脚本、应用程序或系统命令。一般简单的方法是将测试代码放到所需的远程服务器上来运行,或者使用staf框架来协助远程执行。
但我个人认为,staf框架比较适合用于执行sudo权限的命令,而且他对服务器环境有一些额外的要求,比如远程服务器和本机均必须安装staf,而且执行输出结果也不是很清晰。
那有没有轻量级的远程执行方法,并且能将执行结果完整的输出呢?在这里要感谢我以前的同事:一环同学,是他提供了这个宝贵的经验,采用JAVA源码提供的工具: ch.ethz.ssh2
解决方案:
首先介绍ch.ethz.ssh2的一些方法:
1. ch.ethz.ssh2.Connection:
Connection对象,用于与一台SSH-2 服务器建立加密的TCP/IP连接;
2. authenticateWithPassword方法:
在连接建立成功之后,向远程服务器发起认证。该方法通过用户名+密码的方式来进行验证。
如果验证阶段完成,将会返回true。如果远程服务器拒绝请求或者需要进一步的验证操作,则返回false。
3. openSession方法:
在连接建立完成且验证通过之后,打开一个新的会话用于后续的程序执行操作。tips:一个连接可以打开多个会话。
4. ch.ethz.ssh2.Session:
会话对象,是用于执行远程程序的。这个程序包含了shell脚本、应用程序、系统命令。tips:多个会话可以同步执行。
5. execCommand方法:
用于在远程服务器上执行命令。
6. startShell方法:
用于在远程服务器上启动shell脚本。
还有其他对象和方法在这里先不进行介绍,大家有兴趣可以参见开源文档或代码——http://www.java2s.com/Open-Source/Java-Document/Net/Ganymed-SSH-2/ch/ethz/ssh2
其次介绍使用这些方法的代码实现:
/**
* @author gongyuan.cz
*/
public class HelpProc {
private static Connection conn;
private static Session session;
// 建立本机与远程机器之间的连接及验证关系
// ShellServer对象内包含远程主机IP地址,用于操作远程程序的帐号及密码
private static void initSession(ShellServer server) throws IOException {
// 建立本机与远程服务器的连接
conn = new Connection(server.getHost());
conn.connect();
// 在该连接上建立验证关系
boolean success = conn.authenticateWithPassword(server.getUsername(),
server.getPassword());
// 通过Junit来验证验证关系是否通过
Assert.assertTrue("ssh远程服务器失败", success);
// 验证关系通过之后,建立本机与远程服务器的会话
session = conn.openSession();
}
// 执行远程服务器的程序
// ShellServer在上面介绍过
// cmd传入所要执行的命令
// expectStdout是预期该命令执行后的正常输出结果
// expectStderr是预期命令执行后的错误输出结果
public static void executeRemoteCommand(ShellServer server, String cmd,
String expectStdout, String expectStderr) throws Exception {
// 建立连接创建会话
initSession(server);
// 通过会话在远程服务器上执行命令
session.execCommand(cmd);
// 通过BufferedReader获取会话的正常输出结果
BufferedReader stdout = new BufferedReader(new InputStreamReader(session.getStdout()));
try {
String line = stdout.readLine();
StringBuffer sb = new StringBuffer();
while (line != null) {
sb.append(line);
line = stdout.readLine();
}
// 此处可以设置输出远程服务器执行命令后的所有正常输出结果,便于测试人员在本地调试代码
System.out.println(sb.toString());
// 此处验证远程服务器执行命令后的正常输出结果与我们的预期结果是否一致
Assert.assertEquals("内容不匹配", true,sb.toString().contains(expectStdout));
} catch (IOException e) {
e.printStackTrace();
}
// 通过BufferedReader获取会话的错误输出结果
BufferedReader stderr = new BufferedReader(new InputStreamReader(session.getStderr()));
try {
String line = br2.readLine();
StringBuffer sb = new StringBuffer();
while (line != null) {
sb.append(line);
line = br2.readLine();
}
// 此处可以设置输出远程服务器执行命令后的所有错误输出结果,便于测试人员在本地调试代码
System.out.println(sb.toString());
// 此处验证远程服务器执行命令后的错误输出结果与我们的预期结果是否一致
Assert.assertEquals("内容不匹配", true,sb.toString().contains(expectStderr));
} catch (IOException e) {
e.printStackTrace();
}
// 此处会block住直到SSH2的某种状态返回
session.waitForCondition(ChannelCondition.EXIT_STATUS, 0);
// 返回远程命令执行结束的状态码,与Staf的返回码作用一致
int status = session.getExitStatus();
// 输出状态码便于测试人员调试代码
System.out.println("exit_code=" + status);
// 最后关闭会话和连接
session.close();
conn.close();
}
}
最后是代码执行及结果展示:
所执行的代码:
String cmd = "cat " + "/home/admin/test.txt";
HelpProc.executeRemoteCommand(SERVER, cmd, "test file", "");
test file
exit_code=0
ok,以上就是Nginx测试中如何实现远程执行程序的说明。希望能帮助其他测试工程师更高效的完成工作。