【问题标题】:Selenium to check log filesSelenium 检查日志文件
【发布时间】:2015-05-05 12:11:00
【问题描述】:

有谁知道是否可以使用 selenium WebDriver(我使用 java)来检查日志文件中的消息?

目前,了解我们系统前端的操作是否已完成的唯一方法是通过 ssh 进入我们的服务器并等待来自日志文件的确认。这就是手动测试该过程的方式,但现在我需要自动化该测试。是否可以使用 selenium 进行检查?

我目前的实现方法似乎过于复杂:

  • 在前端运行操作
  • 启动 shell 脚本以检查来自 Selenium Test 的日志文件(包括 ssh 到服务器,因为日志存储在那里)
  • 如果日志显示操作已完成,则在服务器上的简单文本文件中创建“操作已完成”消息,否则显示“操作未完成”
  • scp 文件回到我的机器/VM
  • 将文件读入eclipse
  • 在测试中创建方法以检查文件内容,例如 if(返回“操作完成”消息 -> 继续) else(从要点 2 重复)

有没有更简单的方法???

【问题讨论】:

  • Selenium 不太适合这个。您是否使用测试框架(JUnit/TestNG)来执行测试?如果是这样,您可以使用任何 Java 方式来实现它。
  • 是的,我正在使用 JUnit 来执行测试。虽然使用 java,但我仍然遇到与检查需要 ssh 到服务器的日志、对日志运行检查并将结果发送回我的机器相同的问题。有没有更好的办法?
  • 操作完成可以通过在导航到新页面时识别元素更改来找到,或者我们可以保留一个全局变量,在执行事务时可以设置为真/假(如在 Echo 用户界面中- EchoServerTransaction.active="true/false")。
  • 感谢大家快速详细的回复。我考虑了大家所说的一些内容,因为我认为我找到了一个更简单的解决方案。如果您有兴趣,我现在以单独的方法运行所有 shell 命令,并将日志文件的输出带回我的 Eclipse 控制台。从那里可以很简单地在输出上运行正则表达式命令并在一个地方执行进一步的操作。它似乎工作得很好。下一步是添加多线程代码,这样我就可以在后台检查日志,同时运行其他检查,gulp

标签: java testing selenium selenium-webdriver


【解决方案1】:

自我回答 - 在考虑了所有帖子之后,这是我想出的非常有效的解决方案。我已经编写了一个方法,它允许我使用 Eclipse 中的正则表达式解析日志。下面是带有大量注释的代码,以显示我所做的......

public void checkLogs() throws IOException{
    //create an empty string to hold the output 
    String s = null;

    // using the process API and runtime exec method to directly ssh in the client machine and run any command you like. I need the live logs so I used tail -f
    Process p = Runtime.getRuntime().exec("ssh user@ipaddress tail -f /location/file");
    // use buffered reader to bring the output of the command run on the clinet machine back to the output in eclipse. I also created an output for the error stream to help with debugging if the commands dont work as I am not directly looking at the output when I run the commands on the client machine
    BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));

    BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));

    // For my test I only want to continue with the clicks in the front end once I know the system has been reset. For our system this can only be checked in the logs. So I created a boolean flag  which will only become true once the regex I run matches lines from the output. Use a while loop with != null to check every line of the output
    boolean requestArrived = false;
    while ((s = stdInput.readLine()) != null) {
        System.out.println(s); // so I can see live what is happening. (great for debugging)
        //search for the specific string that lets me know the system has been started the reset. (can run any regex here)
        if(r.equalsIgnoreCase("system reset request received")){
            System.out.println("***********************************************************************************************");
            // Change the state of the boolean flag to true as we know now that the backend is ready to continue
            requestArrived = true;
        }

        if(t.equalsIgnoreCase("System reset has happened successfully"))// a secondary check to see when the system is ready to continue{
            System.out.println("##############################################################################################");
            //if both string that we are looking for have been received we can continue with the rest of the script
            if (requestArrived) {
                break;
            }
        }
    }
    //close the terminal 
    p.destroy();

}

我希望对某人有所帮助:)

【讨论】:

  • 你在回答你自己关于使用硒的问题时甚至没有使用硒。
【解决方案2】:

向您的站点添加一个跟踪日志文件的特殊页面。如果您需要对日志文件保密,请拥有 selenium 知道的共享秘密和站点。然后只需访问该页面并使用常用方法检查字符串

可能需要克服一些权限问题:通常 Web 应用程序不应该能够看到日志。

【讨论】:

    【解决方案3】:

    根据您描述的当前解决方案,Selenium 并不是真正适合这项工作的工具(即使您可能会找到解决方案)。

    我可以看到几种可能的方法:

    1. 添加一个显示进度的页面(按照 Vorsprung 的建议)。这可能是一个单独的页面,也可能是现有 GUI 中的一些消息。这可能仅适用于 Selenium,或者如果它对您的系统有意义,它甚至可能成为所有用户(或仅适用于管理员)的适当功能。
    2. 使用您描述的系统,但在本地系统上运行服务器(作为特殊测试实例)。然后您可以跳过 SSH。
    3. 在服务器上创建一些服务(REST 或类似的)来查询作业状态。同样,这可能不仅仅用于测试。

    什么是有意义的取决于系统的使用方式(用户当前如何检查工作是否已完成,有关工作的哪些信息是有趣的,等等)。

    【讨论】:

    • 感谢大家快速详细的回复。我考虑了大家所说的一些内容,因为我认为我找到了一个更简单的解决方案。如果您有兴趣,我现在以单独的方法运行所有 shell 命令,并将日志文件的输出带回我的 Eclipse 控制台。从那里可以很简单地在输出上运行正则表达式命令并在一个地方执行进一步的操作。它似乎工作得很好。下一步是添加多线程代码,这样我就可以在后台检查日志,同时运行其他检查,gulp
    • @DanielCohen:很高兴您找到了解决问题的方法。考虑将您的解决方案添加为答案 - 此处鼓励自行回答,以帮助遇到相同问题的其他人。
    【解决方案4】:

    编辑:我误读了您的问题,因为您要求更简单的解决方案,但我试图为复杂的方法提供解决方案。无论如何,我希望它会有用。

    实际答案:

    我为我的项目完成了以下活动

    1. 在远程 unix 服务器上使用 shell 脚本清除日志
    2. 执行前端活动
    3. 在预定义时间(例如 60 秒)后捕获日志
    4. Sftp 返回客户端计算机

    首先你需要一个 SFTP 客户端和 SSH 客户端来与 unix 服务器交互 这里 Node 是一个包含 Unix 环境细节的对象。所以相应地改变。 为此使用 JSch

    public static String runCommand(String Command, Node node )
    {
        String output = null;
        if (node.getConnType().equals("SSH")){
            int exitStatus = 0;
            try{
                  JSch jsch=new JSch();  
    
                  JSch.setConfig("StrictHostKeyChecking", "no"); 
    
                  Session session=jsch.getSession(node.getUserName(), node.getHost(), 22);
    
                  session.setPassword(node.getPassword());
                  session.setConfig("PreferredAuthentications",
                             "publickey,keyboard-interactive,password");
    
                  session.connect();
    
                  String command=Command;
    
                  Channel channel=session.openChannel("exec");
                  ((ChannelExec)channel).setCommand(command);
    
                  channel.setInputStream(null);
                  ((ChannelExec)channel).setErrStream(System.err);
                  InputStream in=channel.getInputStream();
                  channel.connect();
    
                  byte[] tmp=new byte[1024];
                  while(true){
                    while(in.available()>0){
                      int i=in.read(tmp, 0, 1024);
                      if(i<0)break;
                      output = new String(tmp, 0, i);
                    }
                    if(channel.isClosed()){
                      if(in.available()>0) continue; 
                      exitStatus= channel.getExitStatus();
                      //System.out.println("exit-status: "+exitStatus);
                      break;
                    }
                    try{Thread.sleep(1000);}catch(Exception ee){}
                  }
                  channel.disconnect();
                  session.disconnect();
                }
                catch(Exception e){
                  e.printStackTrace();
                }
               if (exitStatus == 0)
               {
                   if(output != null)
                       return output.replaceAll("[\\n\\r]", "");
               }
        }
        return null;
      }
    

    SFTP 客户端

    public boolean transferFileSFTP(Node node,String srcDir,String targetDir,String srcFileName,String targetFileName, String direction)
     {
        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession(node.getUserName(), node.getHost(), 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setConfig("PreferredAuthentications", 
                    "publickey,keyboard-interactive,password");
            session.setPassword(node.getPassword());
            session.connect();
    
            Channel channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftpChannel = (ChannelSftp) channel;
            System.out.println("src:" + srcDir+srcFileName );
            System.out.println("target:" + targetDir+targetFileName );
            sftpChannel.get(targetDir+targetFileName, srcDir+srcFileName);
            sftpChannel.exit();
            session.disconnect();
            return true;
        } catch (JSchException e) {
            e.printStackTrace(); 
        } catch (SftpException e) {
            e.printStackTrace();
        }
        return false;
    }
    

    现在, 等到所需时间并使其基于线程以同时从涉及的不同应用程序收集日志, 使用 ExecutorServiceFuture 实用程序

    因此创建了一个 LogCollector 类来发起请求,另一个是 ThreadClass(logical),它将在日志文件上执行活动。

    LogCollector.java

    public class LogCollector {
    
        private static ExecutorService pool = Executors.newFixedThreadPool(100);
        private static List<Future<String>> list = new ArrayList<Future<String>>();    
    
        public static void add(Node node, String srcDir, String targetDir, String srcFileName, String targetFileName, long wait )
        {
            list.add(pool.submit(new LogCollectorThread(System.currentTimeMillis()/1000,wait, srcDir,  targetDir,  srcFileName,  targetFileName, node )));                      
        }
    
        public static void getResult()
        {   
            try{
                for (Future<String> future : list) {
                    String out =future.get();
                    //DO whatever you want to do with a response string return from your thread class
                }
                pool.shutdown();
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }     
        } 
    
    } 
    

    LogCollectorThread.java

    public class LogCollectorThread implements Callable<String>{
        long startTime;
        long wait;
        String srcFileName;
        String targetFileName;
        String srcDir;
        String targetDir;
        Node node;
    
        public LogCollectorThread(long startTime, long wait,String srcDir, String targetDir,String srcFileName, String targetFileName, 
                 Node node) {
            super();
            this.startTime = startTime;
            this.wait = wait;
            this.srcFileName = srcFileName;
            this.targetFileName = targetFileName;
            this.srcDir = srcDir;
            this.targetDir = targetDir;
            this.node = node;
        }
        /***
         * Returns a String with Parameters separated by ',' and status at the end 
         * status values:
         *   0 - successfully retrieved log file
         *   1 - failure while retrieving log file
         */
        @Override
        public String call() throws Exception {
            while((System.currentTimeMillis()/1000 - startTime)<=wait)
            {
                Thread.sleep(1000);
            }
            MyFTPClient sftp= new MyFTPClient();
            boolean result =sftp.transferFileSFTP(this.node, this.srcDir, this.targetDir, this.srcFileName, this.targetFileName, "From");
            System.out.println(this.node.getHost() + ","+ this.srcDir + ","+this.targetDir +","+ this.srcFileName +","+ this.targetFileName);
            if(result == true)
                return this.node.getHost() + ","+ this.srcDir + ","+this.targetDir +","+ this.srcFileName +","+ this.targetFileName +"," + "0" ;
            else
                return this.node.getHost() + ","+ this.srcDir + ","+this.targetDir +","+ this.srcFileName +","+ this.targetFileName +"," + "1" ;
         }
    }
    

    如何使用 LogCollector 类:

     String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime());
        Helper.runCommand("cd /opt/redknee/app/crm/current/log/; echo > AppCrm.log", testEnv.getBSS());
    
        LogCollector.add(testEnv.getBSS(), "collectedLogs\\", "/opt/redknee/app/crm/current/log/", timeStamp + "_" + testEnv.getBSS().getHost() + "_BSS_AppCrm.log"  , "AppCrm.log", 60);
    
        //So your thread is working now, so now perform your Front End Activity
        //After 60 seconds, log file will be SFTPed to client host
        //You can perform you activity before adding logCollectorThread or just before that
    
        LogCollector.getResult();
    

    这里我给出了太多的代码, 但是逐行描述每一步太难了。 我想证明的主要事情是使用 java 大部分事情都是可能的。 由您决定它的重要性以及是否值得做。

    现在满足您搜索特定字符串的确切要求。

    正如您在 logCollectorThread 中看到的, 目前我什么也没做,只是等到 60 秒完成。 所以在这里你可以使用 runCommand 从日志中 grep 所需的字符串 你可以使用像

    这样的命令
     grep -i  "Action Completed" | grep -v 'grep' | wc -l
    

    如果它返回 1,你找到了你的字符串 同样,您可以检查失败消息。 并从您的线程返回所需的字符串,并将其作为 threadCollector.getResult() 方法的结果。

    一旦文件通过 FTP 传输到您的客户端,使用 Java 将其解析为特定字符串将非常容易。 StackOverflow 将在这方面为您提供帮助:)

    声明者:不要期望代码能够完全正常工作。 它会起作用,但你必须付出你的努力。插入缺失的部分需要您的 Java 知识

    【讨论】:

      【解决方案5】:

      要检查操作是否已完成,检查服务器日志可能是一种解决方案。但仍然在 GUI 中,我们可以看到一些 html 元素或消息或 java 脚本变量或覆盖 javscript 函数的可见性。

      Selenium JavscriptExecutor 的帮助下,我们可以覆盖alert method(参见示例 21),类似地,我们可以覆盖 onreadystatechange 以完成请求/响应。

      通过检查after each ajax request,可以使用JavaScript 窗口变量来显示操作的完整性。

      我们可以使用 selenium wait 来等待一个元素可见,识别一个元素using xpath

      下面的链接中有更多关于元素等待、输入文本框等的教程。 http://software-testing-tutorials-automation.blogspot.com/2014/05/selenium-webdriver-tutorials-part-two.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-02
        • 2013-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-15
        相关资源
        最近更新 更多