记录阿里巴巴QA架构组成长点滴。2008年关键词为效率,技术,影响力!QA/测试架构师定义:开发和设计测试框架测试库;纵横全局的考虑产品的功能,设计复杂的测试系统;负责研发某一项特定的测试技术;为公司考虑如何提高测试效率。领导公司测试技术的发展和测试策略上的方向,关注整个公司的测试部门的问题,前瞻性的考虑未来的版本的测试策略和技术。测试架构师计划/设计测试平台,关注着产品的测试过程,提供咨询服务,影响到公司内的测试机构测试社区,以及开发机构等,对产品各个方面施加深远而正确的影响,最终提高整体软件质量。

发布新日志

  • bash3.0的新特性-ps命令

    2008-09-24 16:59:00

    ps命令中的status状态 bash3.0以上支持(kernel 2.6以上)
        D Uninterruptible sleep (usually IO) 
        R Running or runnable (on run queue) 运行中
        S Interruptible sleep (waiting for an event to complete) 可打断的后台进程,类似守护进程httpd、ntpd、crond等
        T Stopped, either by a job control signal or because it is being traced. 
        W paging (not valid since the 2.6.xx kernel) 
        X dead (should never be seen) 
        Z Defunct ("zombie") process, terminated but not reaped by its parent. 

        For BSD formats and when the stat keyword is used, additional characters may be displayed: 
        < high-priority (not nice to other users) 高优先级
        N low-priority (nice to other users) 低优先级
        L has pages locked into memory (for real-time and custom IO) 
        s is a session leader 主进程
        l  is multi-threaded (using CLONE_THREAD, like NPTL pthreads do) 表示线程
        + is in the foreground process group 前台运行
     
        譬如:ps -axuf后status column中:Ss表示父进程、R+正在前台运行的进程、SN表示低优先级的进程,S+、Sl表示线程、SL等
  • bash3.0的新特性-history命令

    2008-09-24 16:36:50

    bash3.0之后,history命令推出一个新的常量

    HISTTIMEFORMAT变量:记录历史命令的执行时间

    譬如:HISTTIMEFORMAT="[%F %T]"

    执行history,显示:

    490  [2008-07-16 15:12:23]HISTTIMEFORMAT="[%F %T]"
    491  [2008-07-16 15:12:25]history
    492  [2008-07-16 15:12:32]man date

    在监控用户何时使用了哪个具体的命令,监控用户行为方式有很大的用处

  • 利用托盘程序显示自动化执行进度

    2008-09-17 11:12:36

    by jiale

    在自动化执行过程中需要显示自动化执行的进度,如果使用msgbox,就需要人工干预,且无法一直显示执行进度并实时刷新,理想的结果是脱离qtp且能够实时得到执行的进度。

    在自动化执行过程中将执行进度写入文本文件,利用windos托盘程序,实时读某文件,且利用托盘程序并可显示或隐藏进度窗口。

    vb托盘程序在网上可以轻易找到,不再附上。

  • HTTP GET请求传输汉字给SPRING MVC的处理

    2008-09-15 12:58:14

    HTTP GET请求在提交数据给服务器方面和POST有很多差异。比如传输字节数大小,编码要求等。

    HTTP GET请求要求对汉字进行URL 编码。

     

    IE客户端javascrīpt/vbscrīpt代码。

        

     

    <scrīpt language="vbscrīpt">

    Function GetByteCode(ch)   

        code = Asc(ch)          ' -20001

        GetByteCode = Hex(code) ' "B1DF"

    End Function

    </scrīpt>


    <scrīpt language="javascrīpt">

    String.prototype.urlEncode = function() {

        var r = "";

        for (var i = 0; i < this.length; i++) {

            var code = "" + GetByteCode(this.charAt(i));

            if (code.length > 2) {

                var b1 = code.substr(0, code.length - 2);

                var b2 = code.substr(code.length - 2);

                if (i == 0) {

                    //alert("" + code + ", " + b1 + ", " + code.length + ", " + b2);

                }

                r += "%" + b1 + "%" + b2;

            } else {

                r += "%" + code;
            }
        }
        return r;
    }

    </scrīpt>

     

     

     

    调用上述函数编码

    Var  projectname=”项目1”;

    var urlEncoded=projectname.urlEncode();

     var url="insertCheckList.do?projectname="+urlEncoded;

    接下来就是用AJAX  httprequest发送给JBOSS/TOMCAT。

     

     

     

    服务器端SPRING 接收到字符串解码:

     

    public ModelAndView handleRequestInternal(HttpServletRequest request,

               HttpServletResponse response) throws Exception {

     

    String encodeProj = request.getParameter("projectname");

          

               //客户端经过编码后的汉字

              

               String projectname= new String( encodeProj.getBytes( "8859_1" ) , "gb2312" );

               System.out.println(projectname);      

     

    }

  • webtable对象,利用嵌套字典对象来转化,从而具有逻辑意义

    2008-09-10 20:25:07


    by Wiston Li

    页面中存有大量的webtable,利用getcelldata方法,需要指定行、列的index. 但若在页面上用户

    进行操作上排序,数据排列将发生变化,下面的方法,利用嵌套字典对象来转化,从而具有逻辑意义

    表现访问单元格的值,从而减少参考物理单元格。(数据表如附件所示:)

     

     

     Dim oDataTable
     Dim solarExch
     Dim nRows

     set  ōDataTable=objIdentifyPage ("阿里助手","n").WebTable("text:=操作指南.*","index:=0").WebTable("text:=选择.*")
     Set solarExch = CreateObject("scrīpting.Dictionary")
     nRows=oDataTable.rowcount  
     For  nRow=2 to nRows
      symbolKey =oDataTable.getcelldata(nRow,2)
      solarExch.add symbolkey, createObject("scrīpting.Dictionary")
      solarExch(symbolKey).add "quantity", oDataTable.getcelldata(nRow,3)
      solarExch(symbolKey).add "price", oDataTable.getcelldata(nRow,4)
      solarExch(symbolKey).add "oneprice", oDataTable.getcelldata(nRow,5)
      solarExch(symbolKey).add "highprice", oDataTable.getcelldata(nRow,6)
      solarExch(symbolKey).add "situation", oDataTable.getcelldata(nRow,7)
      
     Next

        msgbox solarExch("asf").item("oneprice")'显示附土中,asf(关键词)这一行,一口价的值,并不依赖当前行列的顺序,即便重新排序。
        msgbox solarExch("试纸").item("price")

  • QTP api中大小写敏感的bug

    2008-09-10 19:38:20

    by wiston li

    qtp中提供对webtable对象操作一系列的api方法,今天在对childitem使用时,令我非常晕的是,曾经使用过多次这个方法,今天突然不奏效了,原因就是很简单,传递的web object的class name大小写是敏感的,

    在help里查了半天,也没有具体定义说明,故我称其bug.

     

    dim oDataTable, iRows

    Set ōDataTable = objIdentifyPage (sTitle,"n").

    WebTable("text:=选 词.*", "index:=0").WebTable("text:=选择.*", "index:=0")
    iRows= oDataTable.RowCount

     If iRows >=2  then
      Call reportManager("Pass", "webtable中数据记录检查", "当前数据表中有数据","有记录存在!","")

      Set ōWebLink =objIdentifyPage (sTitle,"n").WebTable("text:=选 词.*", "index:=0").WebTable("text:=选择.*", "index:=0").childItem(winGetRandNum(2, iRows), 2, "Link", 0 ) ' 如果使用childItem(winGetRandNum(2, iRows), 2, "link", 0 ),QTP即会报错。
      oWebLink.click
      objCloseIE sTitle,"1"   

    else
      Call reportManager("Warning", "webtable中数据记录检查", "当前数据表中有数据","没有记录存在, 数据已被误操作删除,请为此关键词准备竞价数据!","")
      
     end if

  • spring+ibatis+velocity+ajax开发WEB应用小结

    2008-09-06 23:14:27

    这二周闭关开发内部配置管理员用的发布需求流程工具。

    主要的技术为:java spring+ ibatis+ velocity+ ajax/javascrīpt/css+mysql。

    IDE: eclipse。

    以下简要描述各个技术点应用状况。

    (1) java spring: spring很好整合了当下成熟的框架,最突出的概念有2点: IOC 和 AOP。
    spring支持ibatis,hibernate等 O/R MAP工具。支持 JSP/Velocity/struct等V层展现。
    另外,有jpetstore经典的例子、台湾林信良的spring2技术手册引导入门。

    可以运行在JBOSS/TOMCAT上,且其轻量。第一个念头就是用它实现。

    偶高频率应用SimpleFormController完成http请求以及响应。

    比较不爽的是,一堆的XML 配置文件。

    2) 数据方面有同步 confluence数据的需求、导入EXCEL数据需求,且数据量不大。故用单机版的MYSQL足够了。

    本次采用gb2312编码保存数据、页面信息。

    3)  O/R映射方面采用ibatis。 ibatis比hibernate轻量,又能自由操作SQL。

    ibatis 在被JBOSS/TOMCAT运行时加载 sql-map文件,如果SQL和数据库、配置文件有错误,将导致deploy失败。

    数据库如何设计得更合理,适应未来应用增加、环境增加是我考虑最多的点。

    4)  界面展现采用velocity。 这个是偶最不熟悉的。

    感觉最麻烦是它的调试。貌似语言能力偏弱,一些复杂类型的读写有困难。 复杂运算都在SPRING内计算。

    后来直接在spring ModelAndView方法,将简单对象或者List、数组保存为 session 在页面间传递。如
    request.getSession().setAttribute("currUsername", user.getUsername());

    5) ajax/javascrīpt/css应用在2个场景:

     第一个是表格的动态增加, 采用ajax定期更新部分页面信息达到提醒功能,一些常用控件(如日期选取),客户端输入验证等
     
     第二个就是界面美化。 基本功能完成后,看到页面太简陋了。偶从http://www.okajax.com/a/200806/062322552008.html 找了一些特效嵌入。

  • 如何修改QTP脚本默认打开/保存的目录?

    2008-08-20 19:44:04

    By Wiston Li

    QTP脚本开发,每次都要打开文件夹,却总是默认从C:\Program Files\Mercury Interactive\QuickTest Professional\Tests来找文件,

    但基于框架开发的脚本,是保存在src\case里的,今天捣腾了一下,其默认的目录是可以修改的,

    修改注册表:

    1, HKEY_current_user\software\MI\QTP\mictest\TestsDirectory

    2, HKEY_local_machine\software\MI\QTP\mictest\TestsDirectory

    修改为:

    D:\svn\10_QAArchitech_scrīpts\src

    重启QTP,看一下,再打开文件是不是已经修改自定义的目录?是不是操作使用起来很爽。。。

    节约个几秒是几秒,不要把心情弄槽。。。

     

     

  • [论坛] jmeter应用指南(脚本设计、场景设置、查看监控)

    2008-08-19 11:13:42

    by jack
        一直以来都希望能有一套能够基本满足常规性能测试需求,并有效产生报表的工具,用以部分替代LoadRunner的依赖。所以专门针对jmeter进行了评估和研究,在评估过程中完成了一份使用说明;经过代码研究,对jmeter进行了改进,主要是增加了linux资源监控功能和报表功能。由于时间仓促,对增加的代码只进行了单元测试。
        可用于面向B/S WEB应用测试的工程师使熟悉jmeter使用,章节安排按照脚本设计、场景设置、查看监控三部分顺序组织。十四、十五两章内容是关于增进的监控和报表功能的,不适用于apache网站提供的原jmeter。
        内容主要是使用上的,不涉及性能测试分析的内容。

    Jmeter应用指南.pdf
    (2008-08-19 11:13:16, Size: 1.45 MB, Downloads: 0)

  • 测试工具loadrunner扩展开发的一点感想

    2008-08-13 22:39:46

      by liangjz

      最近在应用VC6,大量采用win32 api扩展Loadrunner8.0/8.2的一些外围功能,做到自动调节面向资源消耗目标的合适(临界)并发数,碰到了几个相当棘手问题。

      (1) 在loadrunner controller design 界面上编程实现更改并发用户数
      (2) 确保安全停止在运行的loadrunner但不破坏已存在结果文件,如res.lrr等等

      由于没有loadrunner源代码以及很detail的介绍Loadrunner内部结构的资料,为了突破这些点,耗费了相当的力气。
      如果我们换成对JMeter的外围扩展内,在一堆结构清晰的代码面前,突破这些功能难度可能陡降

    经过这些天的尝试,对扩展黑盒工具的难度有一个更加清晰的认知,实践才知道水有多深

    下面简单介绍下如何做到编程更改loadrunner并发数的几个思路

         1)EnumWindows/GetWindowText 结合spy++,硬编码检索到窗口层次关系,获取classname=GridControl、windows caption=GridClass的控件,然后利用grid控件的行、列改写数据。

    可是classname=GridControl仅仅是注册窗口时的一个友好名字,并非真正实现类。这个实现这个控件的类是什么呢? 这下卡壳了。

    从安全工程师哪边拿到LookingGlass.exe、FABERTOYS(进程管理).EXE等工具,企图嗅探出ocx但未果。

    其他难度、实现成本比较高、非常笨拙操控grid的方式还有: 利用IDAPro动态调试或者进程注入修改对应内存内容,这个有时间再琢磨下。

        2)修改loadrunner 场景设计文件.lrs的GroupChief内容

    由于loadrunner controller designed 界面大量选项,每一个选项可能都对loadrunner结果产生敏感影响。为了弄清楚每一个选项对应文件内容,很土也很管用的方法
    一次只更改一个,然后对比变化,最后跟踪发现groupchief 段才是loadrunner 并发数关键所在。

    lrs文件格式不是Ini 格式,是mercury自有格式,我们要做的事情就是fgets逐行读取,然后填充入自定义的数据结构(偶采用了链表)。

    增加、删除修改并发数就是减少ChiefSettings所在的段,最后用fwrite将数据结构回填。

    最后第二个方法成功实现需求。

    不过综合权衡下,如果loadrunner升级lrs数据结构,第二种方法是相当脆弱的。

    哈,要是偶遇一个mercury工具研发工程师问到grid控件实现类并把头文件和lib给我,然后彻底解决这个问题该多好啊

  • 标准时间和格式化时间的转换-awk

    2008-08-12 19:14:55

    date命令和strftime函数,扩展clock、hwclock

         date命令:print or set the system date and time

         strftime函数:awk调用了类型为time_t的c函数库  strftime([format [, timestamp]])

                功能:Formats  timestamp  according to the specification in format.

         systime函数:同上,Returns the current time of day  as  the  number  of  seconds since the Epoch   systime()

         譬如:毫秒级时间戳->格式化时间:echo 12879350 | awk '{print strftime("%F %T", $0)}'

    格式化时间->毫秒级时间戳:date -s把当前时间设置成special time,然后 awk '{print systime()}'即可

  • 使用samba的提高工作效率

    2008-08-12 17:38:29

    samba
    service smb stop/start/status
    /etc/samba/smb.conf

    然后我们把下面这段写入smb.conf中;

    [global]
    workgroup = LinuxSir
    netbios name = LinuxSir05
    server string = Linux Samba Server TestServer
    security = share
    [linuxsir]
            path = /opt/linuxsir
            writeable = yes
            browseable = yes
            guest ōk = yes

    注解:

    [global]这段是全局配置,是必段写的。其中有如下的几行;

    workgroup 就是Windows中显示的工作组;在这里我设置的是LINUXSIR (用大写);
    netbios name 就是在Windows中显示出来的计算机名;
    server string 就是Samba服务器说明,可以自己来定义;这个不是什么重要的;
    security 这是验证和登录方式,这里我们用了share ;验证方式有好多种,这是其中一种;另外一种常用的是user的验证方式;如果用share呢,就是不用设置用户和密码了;

    [linuxsir] 这个在Windows中显示出来是共享的目录;
    path = 可以设置要共享的目录放在哪里;
    writeable 是否可写,这里我设置为可写;
    browseable 是否可以浏览,可以;可以浏览意味着,我们在工作组下能看到共享文件夹。如果您不想显示出来,那就设置为 browseable=no

    guest ok 匿名用户以guest身份是登录;

    第二步:建立相应目录并授权;

    在linux下:smbclient -L 192.168.1.101

    在window下:\\192.168.1.101
    注意iptables stop
    注意修改/etc/samba/smb.conf下的host allow的IP设
  • tcpdump在服务器维护方面的使用

    2008-08-12 17:24:56

       在表达式中一般如下几种类型的关键字:

       第一种是关于类型的关键字,主要包括host,net,port

       例如  host 210.27.48.2, 指明 210.27.48.2是一台主机

       net 202.0.0.0,指明202.0.0.0是一个网络地址

       port 23 指明端口号是23。如果没有指定类型,缺省的类型是host。

       第二种是确定传输方向的关键字,主要包括src,dst,dst or src,dst and src,这些关键字指明了传输的方向。

       举例说明,src 210.27.48.2 ,指明ip包中源地址是 210.27.48.2 , dst net 202.0.0.0 指明目的网络地址是202.0.0.0。

       第三种是协议的关键字,主要包括fddi,ip,arp,rarp,tcp,udp等类型。

       还有三种逻辑运算,取非运算是not,!  ;与运算是and,&& ;或运算是or ,||

       example:

         1. tcpdump port 23 and \( host 192.168.1.101 \) :    过滤主机192.168.1.101(不管src还是dst)且端口为23的包

         2. tcpdump host 192.168.1.1:    截获所有192.168.1.1主机收到的和发出的所有的包

         3. tcpdump ip host 210.27.48.1 and ! 210.27.48.2:    获取主机210.27.48.1除了和主机210.27.48.2之外所有主机通信的ip包

         4. tcpdump host 210.27.48.1 and \(210.27.48.2 or 210.27.48.3 \):    截获主机210.27.48.1 和主机210.27.48.2或210.27.48.3的通信

         5. 先 tcpdump 一看,信息太多。 想了想我要做的是什么,主要是想看看,局域网中访问internet那些东西,跟那些机器有连接,而且要探测不明链接。从而可以发现是否有木马,病毒一些在作怪! tcpdump dst net not 192.168.123.0/24 不监视跟网内机子的链接,过滤很多信息。迅速进入主题, 不想看发邮件的情况,一般的80网页访问,domain访问,还有要排除网内已有服务器的一些端口。

  • 异常对象识别(Watir应用解决方案)

    2008-08-11 19:29:18

    5. 异常对象识别(Watir应用解决方案)

    Watir基于处理,继承于web document的对象提供较好的支持方法,但相对于处理windows对象较弱. 就目前从各网站收集的对象来看, 基本上,对于在IE实例对象打开的web标准对象
    能够成功识别与操作,其它的脱离当前IE窗口,打开的所有弹出框都不能正常识别。其中,弹出框对象占有异常对象识别中很大一部分。
    目前碰到的弹出框, 我把他们分为三大类型:
    1, Alerts 警告作用,如:sorry, 当前用户没有权限操作
    2, Confirm 需要操作按钮, 如:你确认要删除当前记录?
    3, Prompt+ select +confirm  需要用户输入,操作查询或点击, 最后确认, 如:Download/upload (浏览+选择文件)

    下面给出,上面几种弹出框watir实现识别与操作的方法,
    5.1. 弹出框基于autoIT + 线程实现方式

    此种方法,对于第一、二种弹出框操作较有效,
    因点击某个link/button等对象,而弹出的窗口(大部分弹出框可应用此种方式来实现。)

    1, 定义方法

    def check_for_popups
        autoit = WIN32OLE.new('AutoItX3.Control')
        #
       
        # Do forever - assumes popups could occur anywhere/anytime in your application.
        loop do
            # Look for window with given title. Give up after 1 second.
           
            ret = autoit.WinWait('消息 -- 网页对话框', '', 1)
            #ret = WinActivate("Microsoft Internet Explorer", "")
    #autoit.ControlClick("Microsoft Internet Explorer", "", "[CLASS:Button; INSTANCE:1]", 2)
           
            puts(ret)
            #
            # If window found, send appropriate keystroke (e.g. {enter}, {Y}, {N}).
           
            if (ret==1) then autoit.Send("{Enter}") end
           
            #
            # Take a rest to avoid chewing up cycles and give another thread a go.
            # Then resume the loop.
            sleep(3)
        end
      end


    2, 程序体代码

    ie.button(:name, "signin").click_no_wait

    sleep(20)

    $popup = Thread.new { check_for_popups }  # start popup handler

    at_exit { Thread.kill($popup) }

     


    5.2. Call 另一ruby文件

    对于第二种弹出框,像安全警告点击, 并不通过操作与点击任何对象, 即呈现弹出窗口。
    我尝试用3.1方法来实现,不成功。用下面方法替代:


    1, 在watir/WindowHelper.rb文件中增加方法

       def push_security_alert_yes_cn
            @autoit.WinWait "安全警报", ""
            @autoit.Send "{TAB}"
            @autoit.Send "{TAB}"
            @autoit.Send "{SPACE}"
          End

    2, 定义另一调用文件 tmp.rb
    require 'watir/WindowHelper'
    helper = WindowHelper.new
    helper.push_security_alert_cn_yes


    3, 在打开安全URL之前,启动调用ruby文件

    require 'rubygems'
    require 'watir'   # the watir controller
    require 'win32ole'
    require 'watir/WindowHelper'


    Thread.new{system('ruby c:\tmp.rb')} #你定义tmp文件存放路径
    ie = Watir::IE.new
    ie.goto("http://www.alipay.com.cn/")
    5.3. 修改框架底层

    此种方法,针对弹出框3.

    举例一, 上传下载文件
    1, 修改底层代码input_elements.rb文件,
    类 FileField中, 方法set.
    为了支持中文,有一句替换修改为:

    system("rubyw -e \"require 'win32ole'; @autoit=WIN32OLE.new('AutoItX3.Control'); waitresult=@autoit.WinWait '选择文件', '', 15; sleep 1; if waitresult == 1\" -e \"@autoit.ControlSetText '选择文件', '', 'Edit1', '#{setPath}'; @autoit.ControlSend '选择文件', '', 'Button2', '{ENTER}';\" -e \"end\"")


    2, 定义方法
    def save_file(filepath)
        ai = WIN32OLE.new("AutoItX3.Control")
        ai.WinWait("文件下载", "", 5)
        ai.ControlFocus("文件下载", "", "保存(&S)")
        sleep 1
        ai.ControlClick("文件下载", "", "保存(&S)", "left")
        ai.WinWait("另存为", "", 5)
        sleep 1
        ai.ControlSend("另存为", "", "Edit1",filepath)
        ai.ControlClick("另存为", "", "保存(&S)", "left")
        ai.WinWait("下载完毕", "", 5)
        ai.ControlClick("下载完毕", "", "关闭")
      end


    3, 程序体代码:
    ie.file_field(:name, "xlsfile").set("c:\\samenameobject.html")
    #上传你所指定的文件


    ie.span(:text, "导出Excel表").click_no_wait
    save_file("C:\\abc.xls")
    #下载到你所指定的路径

     

    针对弹出框3, 需要用户介入查询并操作:
    举例二, 中供crm中类目与客户选择的弹出框,与第一种实现方式不同在于,
    用到autoit中WinActivate与ControlClick方法,


    require 'rubygems'
    require 'watir'   # the watir controller
     require 'watir/WindowHelper'
     
    require 'win32ole'


    def check_for_popups
     
    autoit = WIN32OLE.new('AutoItX3.Control')

    loop do
          ret = autoit.Winwait("选择 -- 网页对话框", "", 1)
          puts ret
         if (ret==1) then
           autoit.WinActivate("[CLASS:Internet Explorer_TridentDlgFrame]", "")
          autoit.Send("{TAB}")
          autoit.Send("{TAB}")

          #autoit.Send("湖州")
          #autoit.Send("{ASC 2709}")
          #autoit.SendUnicode("a")
          #autoit.ClipPut ("杭")
          #autoit.ClipGet
          #autoit.ToolTip "This is a tooltip杭州", 0, 0
          #autoit.Sleep 2000  
         
          autoit.Send("{TAB}")
          autoit.Send("{TAB}")
          autoit.Send("{Enter}")

          autoit.WinActivate("[CLASS:Internet Explorer_TridentDlgFrame]", "")
          autoit.ControlClick("选择 -- 网页对话框", "", "[CLASS:Internet Explorer_TridentLstBox; INSTANCE:2]", 2)

          autoit.Send("{TAB}")
          autoit.Send("{Enter}")

          autoit.Send("{TAB}")
          autoit.Send("{TAB}")
          autoit.Send("{TAB}")
          autoit.Send("{TAB}")
          autoit.Send("{Enter}")
        end
        sleep(3)
      end

    end


    ie=Watir::IE.new
    ie.goto("http://10.2.6.4:5100/bin/member/signin")
    #ie.goto("http://10.2.6.4:5100/")


    #ie.element_by_xpath("//span[contains(text(), 'Main Road Nijmegen')]").click

    ie.text_field(:name, "id").set("mhl1805") 
    ie.text_field(:name, "password").set("zxcvbnm")

    ie.button(:name, "signin").click


    ie.frame(:name, "left").link(:url, "http://10.2.6.4:5100/v3/help_cust.htm").click

    ie.frame(:name, "left").link(:text, "新签中供客户").click

     # start popup handler


    ie.frame(:name, "right").frame(:name, "rtop").button(:value, "选择客户").click_no_wait
    sleep(20)

    $popup = Thread.new { check_for_popups }

    at_exit { Thread.kill($popup) }

    针对第三种popup window, 如果需要与用户交互,且需要输入中文时,若用autoit sendkey对待中文支持(但官方文档说支持中文输入, 网上有不少人和我遇到同样问题),尚没有找到有效方案,有待进一步跟进。

       除上述弹出框需要特殊处理外,watir中也有一些扩展tag,或第三方控件需要特殊处理的,
       像:
    5.4. web HTML编辑器
    中文站的html编辑器提供: 操作ID或name操作起来较方便直接

    require 'rubygems'
    require 'watir'   # the watir controller
    require 'watir/WindowHelper'
    require 'win32ole'
    ie=Watir::IE.new

    ie=Watir::IE.attach(:title, /阿里助手/)
     
    ie.text_field(:name, "_fmo.a._0.s").set("mhl1805") 
    ie.document.getElementByid("_editor").contentWindow.focus()
    ie.send_keys("abcsadfasfd")


    但也碰到有些web页面,不提供任何ID,只能用autoIT方法来send tab实现


    require 'rubygems'
    require 'watir'   # the watir controller
    require 'watir/WindowHelper'
    require 'win32ole'


         


    ie=Watir::IE.new

    #ie=Watir::IE.attach(:title, /Alibaba/)

    ie.goto('http://us.my.alibaba.com/product/buyoffer/post_buying_lead.htm')

    ie.text_field(:name, "_fmp.bu._0.su").set("mhl1805") 
    ie.text_field(:name, "_fmp.bu._0.su").set("中国人") 


    ie.checkbox(:id, "detailDesc").set
    ie.checkbox(:id, "detailDesc").focus()
    ie.send_keys("\t"*9)
    ie.send_keys('Hello Worldabcdef')


    5.5. 对象识别其它常用TAG内置方法引用

    如:IE.div , ie.span, ie.cell, ie.table方法,可以实现点击操作,取值操作等.
    另外提供QTP类似描述性编程,同类型对象统计:

    ie.buttons.each { |b| puts b.to_s }
     puts ie.checkboxes.length  
     puts ie.links.length 
     puts ie.buttons.length等等 

    对于常用的innertext属性, 在watir中已经封装到方法,可以直接引用。如:
    ruby在对象识别底层,封装了innertext
    实现,调用方法text即可:
    如:puts ie.div(:id, "intelligentWord").link(:id, index.to_s).text

    最后:返回文本与源代码,用下面方法:
    puts ie.text()
    puts ie.html() 

    5.6. 识别对象正则表达式支持
     
    当然,ruby提供强大的正则表达式支持,如:属性标识正则
    ie=Watir::IE.attach(:title, /Alibaba/)

    Ruby的正则表达式以"//"作为基本框架,表达式内容位于"/"之间。表达式返回一个RegExp的对象。
    表达式的一般规则:
    /a/匹配字符a。
    /\?/匹配特殊字符?。特殊字符包括^, $, ? , ., /, \, [, ], {, }, (, ), +, *.
    .匹配任意字符,例如/a./匹配ab和ac。
    /[ab]c/匹配ac和bc,[]之间代表范围。例如:/[a-z]/ , /[a-zA-Z0-9]/。
    /[^a-zA-Z0-9]/匹配不在该范围内的字符串。
    /[\d]/代表任意数字,/[\w]/代表任意字母,数字或者_,/[\s]/代表空白字符,包括空格,TAB和换行。
    /[\D]/,/[\W]/,/[\S]/均为上述的否定情况。

    关于正则其它用法,请参照《watir技术集锦》
    5.7. 最后攻略

    总之,对于对象识别与操作,要借助于上述文档中的, 灵活运用autoit, xpath与异常对象操作方法。对于watir不支持的windows控件,想到第一个方法,就是采用第三方autoit技术,来模拟键盘或鼠标操作。
    对于操作web对象,watir不支持特殊tag,除了扩展其底层代码外,只能深深研究一下xpath了.
    最后,再搞不定,就只能到watir group里咨询高人了,呵呵。

    尚没有碰到其它更好方法。。。

  • MSXML6 SDK解析中文XML文件

    2008-08-10 01:54:08

    1.1       下载msxml6_SDK.msi安装

     

    http://www.microsoft.com/downloads/details.aspx?familyid=993C0BCF-3BCF-4009-BE21-27E85E1857B1&displaylang=en

     

    默认安装在C:\Program Files\MSXML 6.0\

     

    1.2       vc6上建立编译环境

    Preprocessor 编译加入 Additional include directorie加入C:\Program Files\MSXML 6.0\inc

     

    LINK module加入: msxml6.lib

     

    Link Additional  library path加入:C:\Program Files\MSXML 6.0\lib

    1.3       解决vc6 link错误问题

     

    msxml6.lib(msxml6_i.obj) : fatal error LNK1103: debugging information corrupt; recompile module

     

    参见

    http://www.armleg.com/forum/viewtopic.php?p=388&sid=414fd259dcf02a90f150708296924178&mforum=diodiaforum

     

    All I get from Google is that VS6 doesn't work with platform SDK's later than february 2003.

     

    必须采用release版本编译、链接才成功。(build->set active project configuration->win32 release)

     

     

    1.4       汉语问题

     

           //解决汉语问题

           setlocale(LC_ALL,"chinese-simplified");

     

    1.5       源代码

     

    #include <objbase.h>

    #include <msxml6.h>

    #include <stdio.h>

    #include <windows.h>

    #include <stdarg.h>

    #include <locale.h>

    #include <AtlBase.h>

     

    #import <msxml6.dll> raw_interfaces_only

     

    // Macro that calls a COM method returning HRESULT value:

    #define HRCALL(a, errmsg) \

    do { \

        hr = (a); \

        if (FAILED(hr)) { \

            dprintf( "%s:%d  HRCALL Failed: %s\n  0x%.8x = %s\n", \

                    __FILE__, __LINE__, errmsg, hr, #a ); \

            goto clean; \

        } \

    } while (0)

     

    // Helper function that put output in stdout and debug window

    // in Visual Studio:

    void dprintf( char * format, ...)

    {

        static char buf[1024];

        va_list args;

        va_start( args, format );

           sprintf(buf, format, args);

        vsprintf(buf, format, args );

        va_end( args);

        OutputDebugStringA( buf);

        printf("%s", buf);

    }

     

    // Helper function to create a DOM instance:

    IXMLDOMDocument3 * DomFromCOM()

    {

       HRESULT hr;

       IXMLDOMDocument3 *pxmldoc = NULL;

     

       HRCALL( CoCreateInstance(CLSID_DOMDocument60,

                      NULL,

                      CLSCTX_INPROC_SERVER,

                      //__uuidof(IXMLDOMDocument),

                                  IID_IXMLDOMDocument3,

                      (void**)&pxmldoc),

                      "Create a new DOMDocument");

     

        HRCALL( pxmldoc->put_async(VARIANT_FALSE),

                "should never fail");

        HRCALL( pxmldoc->put_validateOnParse(VARIANT_FALSE),

                "should never fail");

        HRCALL( pxmldoc->put_resolveExternals(VARIANT_FALSE),

                "should never fail");

     

        return pxmldoc;

    clean:

        if (pxmldoc)

        {

            pxmldoc->Release();

        }

        return NULL;

    }

     

    int Get_nodeValue(IXMLDOMElement * pRoot , char * tagName,char *ret_text)

    {

           USES_CONVERSION;

        IXMLDOMNodeList  * pNodeList = NULL;

           IXMLDOMNode  * pNode = NULL;

           HRESULT hr;

           BSTR bstr = NULL;

     

           hr=pRoot->getElementsByTagName(_bstr_t(tagName),&pNodeList) ;

           if (FAILED(hr))

                  return -1;

     

           //取第一个满足条件的

           hr= pNodeList->get_item(0,&pNode);

           if (FAILED(hr))

                  return -1;

          

           hr=pNode->get_text(&bstr);

           if (FAILED(hr))

                  return -1;

           //dprintf("v=%s\n",W2A(bstr));

           sprintf(ret_text,W2A(bstr));

           return 0;

    }

     

    int main(int argc, char* argv[])

    {

      /*

      HRESULT hr;

      IXMLDOMDocument3 *pXMLDoc = NULL;

      CoInitialize(NULL);

      hr = CoCreateInstance(CLSID_DOMDocument60,

                         NULL,

                         CLSCTX_INPROC_SERVER,

                         IID_IXMLDOMDocument3,

                         (void**)&pXMLDoc);

       if (FAILED(hr))

       {

          printf("Error code: %x\n", hr);

       }

    */

           USES_CONVERSION;

        IXMLDOMDocument3 *pXMLDom=NULL;

        IXMLDOMParseError *pXMLErr=NULL;

        BSTR bstr = NULL;

        VARIANT_BOOL status;

        VARIANT var;

        HRESULT hr;

           IXMLDOMElement * pRoot = NULL;

           VARIANT_BOOL isHasChild=VARIANT_FALSE;

           long listLen=0;

           long i=0;

           char ret_scrīpttext[48]={0};

           char ret_steptime[48]={0};

           char sz_xmlFile[]="lr.xml";

          

        CoInitialize(NULL);

           //解决汉语编码问题

           setlocale(LC_ALL,"chinese-simplified");

     

        pXMLDom = DomFromCOM();

        if (!pXMLDom) 

                  goto clean;

          

        VariantInit(&var);

        V_BSTR(&var) = SysAllocString(_bstr_t(sz_xmlFile));

        V_VT(&var) = VT_BSTR;

        HRCALL(pXMLDom->load(var, &status), "");

     

        if (status!=VARIANT_TRUE) {

            HRCALL(pXMLDom->get_parseError(&pXMLErr),"");

            HRCALL(pXMLErr->get_reason(&bstr),"");

            dprintf("Failed to load DOM from stocks.xml. %S\n",

                        bstr);

            goto clean;

          

     

        }

        HRCALL(pXMLDom->get_xml(&bstr), "");

     

        dprintf("XML DOM loaded from stocks.xml:\n%S\n",bstr);

     

           HRCALL( pXMLDom->get_documentElement(&pRoot) ,"get_documentElement");

      

           Get_nodeValue(pRoot,"scrīpt",ret_scrīpttext);

           Get_nodeValue(pRoot,"steptime",ret_steptime);

          

           printf("%s %d",ret_scrīpttext,atoi(ret_steptime));

     /*

        HRCALL(pNode->get_nodeValue(&value),"get_nodeValue");

           USES_CONVERSION;  

        dprintf("v=%s\n",OLE2A(value.bstrVal));

           SysFreeString(bstr);

    */

     

    clean:

        if (bstr) SysFreeString(bstr);

        if (&var) VariantClear(&var);

        if (pXMLErr) pXMLErr->Release();

        if (pXMLDom) pXMLDom->Release();

     

        CoUninitialize();

        return 0;

    }

     

    Lr.Xml文件如下(notepad保存为ascii格式)

    <?xml version="1.0" encoding="GB2312"?>

     

    <root>

        <scrīpt type="string">d:\工程\1.lrr</scrīpt>

        <steptime>30</steptime>

    </root>

  • jmeter利用http代理服务器组件录制脚本

    2008-08-07 19:14:35

    by jack

    在“工作台”添加“HTTP代理服务器”

    端口:

    代理服务器的端口,默认8080,可自行修改,但不要与其它应用端口冲突

    目标控制器:录制的脚本存放的位置,可选择项为测试计划中的线程组

     

    分组:

    对请求进行分组。“分组”的概念是将一批请求汇总分组,可以把url请求理解为组。

           “不对样本分组”:所有请求全部罗列

           “在组间添加分隔”:加入一个虚拟的以分割线命名的动作,运行同“不对样本分组”,无实际意义

           “每个组放入一个新的控制器”:执行时按控制器给输出结果

           “只存储每个组的第一个样本”:对于一次url请求,实际很多次http请求的情况,这个选项很好用,因为我们常常是不关心后面的那些请求的。

     

    记录HTTP信息头:

    录制requesthead信息

    添加断言:

    录制时加入空的检查点(需自行填写内容)

    Regex matching

    录制时加入空的正则匹配(需自行填写内容)

     

    在浏览器中录制

    启动HTTP代理服务器后,打开浏览器(IEFirefoxOpera等),添加代理,地址填写本机iphost name,端口填写刚刚设置的代理端口(本例中8080),在浏览器中进行正常网页浏览,即可录制下对应的http请求。IE上的设置:

  • 自动化友好、干净停止loadrunner运行场景的源代码

    2008-08-01 23:28:10

      最近针对loadrunner做功能扩展,其中一个环节是:尽力正常点击stop停止,如经过处理无法停止,则干净停止loadrunner进程。

      loadrunner手册有命令行方式启动wlrun.exe进程的方式,但没有停止wlrun.exe的方式。本方法用win32实现友好停止Loadrunner场景。

      窗口层次关系可以用spy++察看 .

      测试程序的方法,启动一个loadrunner运行场景。

    #include <stdlib.h>
    #include <stdio.h>
    #include  <time.h>
    #include  <errno.h>
    #include <locale.h>
    #include <windows.h>
    #include <vdmdbg.h>


    typedef struct
       {
          DWORD   dwID ;
          DWORD   dwThread ;
       } TERMINFO ;

      BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) ;


     DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )
       {
          HANDLE   hProc ;
          DWORD   dwRet ;

          // If we can't open the process with PROCESS_TERMINATE rights,
          // then we give up immediately.
          hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE,
             dwPID);

          if(hProc == NULL)
          {
             return FALSE ;
          }

          // TerminateAppEnum() posts WM_CLOSE to all windows whose PID
          // matches your process's.
          EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID) ;

          // Wait on the handle. If it signals, great. If it times out,
          // then you kill it.
          if(WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0)
             dwRet=(TerminateProcess(hProc,0)?TRUE:FALSE);
          else
             dwRet = TRUE ;

          CloseHandle(hProc) ;

          return dwRet ;
       }


    BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam )
    {
      DWORD dwID ;

      GetWindowThreadProcessId(hwnd, &dwID) ;

      if(dwID == (DWORD)lParam)
      {
         PostMessage(hwnd, WM_CLOSE, 0, 0) ;
      }

      return TRUE ;
    }

    //MyEnumWindow 函数本身只能枚举最top-level的窗口。
    //嵌套的窗口自己枚举

    //这里用spy++观察层次结构
    //模拟用户鼠标操作停止loadrunner的过程
    BOOL   CALLBACK    MyEnumWindow(HWND   hWnd,   LPARAM   lParam)
    {
       char    sz_text[MAX_PATH]={0}; 
       int  len =0;
       char  * p_title = NULL;
       int  ret;
       HWND child_hWnd=NULL,dialog_hWnd=NULL,next_hWnd=NULL;
       int  i=0;
       BOOL isFound = FALSE;
       int try_time=10;
       WINDOWINFO  winInfo;
       DWORD dwID ;
       p_title=(char*)lParam;

       len= GetWindowText(hWnd,   sz_text,   sizeof(sz_text)/sizeof(sz_text[0]));  
       if (strstr(sz_text,"LoadRunner"))
            printf("%s\r\n",sz_text); 
       child_hWnd = hWnd;
       if(strstr(sz_text,p_title))  
       {  
          
       while(1)
       {
        //获取子窗口
        child_hWnd=GetWindow(child_hWnd, GW_CHILD);
        //恶意关闭loadrunner时,窗口是否为存在?防止死循环。
        if(child_hWnd!=NULL)
        {
         len= GetWindowText(child_hWnd, sz_text, sizeof(sz_text)/sizeof(sz_text[0]));      
         if (!strcmp(sz_text,"&Start Scenario"))
         {
         //获取兄弟窗口
         next_hWnd=GetWindow(child_hWnd, GW_HWNDNEXT);
         len= GetWindowText(next_hWnd,sz_text,   sizeof(sz_text)/sizeof(sz_text[0]));
         if (!strcmp(sz_text,"S&top") )
         {
          //找到停止的窗口
          isFound =TRUE;
          break;
         }   
         }
        }
        else   //child_hWnd!=NULL
        {
        break;
        }
       } //while

      
       if (FALSE ==isFound )
       {
        //失败退出
        printf("not found S&top!\r\n");
        return TRUE;
       }

       //尝试投递try_time次。
       //for(i=0;i < try_time; i++)
       while(1)
       {

        //SendMessage(next_hWnd,  BM_CLICK,0,  0);
        PostMessage(next_hWnd,  BM_CLICK,0,  0); // 这里不能用SendMessage,否则阻塞进程
        dialog_hWnd  = FindWindow("#32770", "LoadRunner Controller");
       
        if (!dialog_hWnd)   
        {
         printf("Find dialog error.  ret=%d\r\n",GetLastError());
        }
        else 
        {      
         //if  (IsWindowVisible(dialog_hWnd))
         //{
          len= GetWindowText(dialog_hWnd,  sz_text, sizeof(sz_text)/sizeof(sz_text[0]));
          printf("GetWindowText  return %s\r\n",sz_text);          
          //查找对话框上按纽
          child_hWnd  =  FindWindowEx(dialog_hWnd,0,"Button","确定");
          if (!child_hWnd)
          {
           printf("确定 button  ret=%d\r\n",GetLastError());
           continue;
          }

          SendMessage(child_hWnd, BM_CLICK,0,  0);
          ret = GetLastError();
          if (ret)
          {
           printf("button  error. ret=%d\r\n",ret);
          }
          else
          {
            printf("正常停止loadrunner!\r\n");
          }
           //经过如上处理后
          printf("destroywindows\r\n");
           Sleep(10);
           //强行关闭loadrunner相关进程
             GetWindowThreadProcessId(hWnd, &dwID) ;
          TerminateApp(dwID,10);
          return   FALSE;  
         //}
        } //(!prev_hWnd)
       }//for
       } 

       return   TRUE;  
    }
    int stop_loadrunner()
    {

      char    sz_title[]="Mercury LoadRunner Controller ";
      //  char    sz_title[]="S&top";
      if (EnumWindows(MyEnumWindow,(long) sz_title) )
        printf("failed,errno=%d",GetLastError());
     
    }


    void main()

    {

    stop_loadrunner();

    }

  • [论坛] Jmeter Linux资源监控器

    2008-08-01 21:00:22

    by jack

    最近完成了jmeter linux资源监控器的开发,方法并不怎么高明,但相信可以帮助很多用jmeter来做性能测试的同仁解决jmeter缺少linux资源监控的问题
    附件中是编译好的包以及linux上所用的脚本。基本的原理是利用shell脚本生成资源xml,让jmeter利用http请求获取该xml,解析展现数据。
    欢迎各位同仁测试使用,有问题也可以与我交流。

    监控器实现的是linux系统上的资源监控,要求:服务器上至少有一个web server(因需要通过http请求获取资源xml),用于生成服务器资源xml的脚本中使用了sysstat包中的指令,所以需要安装sysstat包。
    使用方法:
    下载:

    LinuxResourcesMonitor.rar
    (2008-08-01 20:56:32, Size: 756 kB, Downloads: 0)


    先解开压缩包,取出status脚本,登录到被监控的服务器上,status脚本放上去。该脚本执行时会在所在路径生成status.xml文件,可以直接将status脚本放在web server的目录下,也可以用软链接来链到status.xml文件。下面介绍在基于apacheweb server上的配置方法:
    apache的配置文件httpd.conf中找到DocumentRoot,一般默认是apache目录下的htdocs,将status脚本放到该目录下;
    更改执行权限:
    chmod 744 status
    启动该脚本:
    ./status start
    启动起来之后就会在当前目录下产生status.xml文件
    不需要监控时,停止该脚本:
    ./status stop




    然后到运行jmeter的机器上,解开压缩包里的ext.rar包,将解压得到的两个jar包:ApacheJMeter_core.jarApacheJMeter_monitors.jar,复制到jmeterlib/ext目录下,覆盖原来的jar包。
    之后就可以到jmeter上来监控了:打开jmeter,建立一个线程组,添加一个http请求,ip就是要监控的服务器地址,端口号就是apache侦听的http端口,协议是“http”,路径是“/status.xml”,勾选“用作监视器”;



    http request.JPG


    再为该http请求添加一个“固定定时器”组件和一个“监视器结果”组件,“固定定时器”的延时要设置为大于1秒的时间,即数据的采样时间。



    timer.JPG


    在线程组中循环次数设置勾选“永远”;



    thread group.JPG


    Run一下,就可以在监视器结果上看到刚刚添加的监控服务器了,目前已经监控了6个参数:cpu%user,cpu%iowait,load,mem%(used/total),swap in,swap out。


    monitor.JPG



    如果被监控的linux上没有安装sysstat包,是无法正常生成监控数据的,这里附上sysstat包的安装方法:
    首先到 http://perso.wanadoo.fr/sebastien.godard/ 下载最新的版本,最好是源码包,比如sysstat-5.1.1.tar.gz

    1.
    解包:


    tar zxvf sysstat-5.1.1.tar.gz



    2.
    安装:


    cd sysstat-5.1.1


    make config
    这步可以省略,有些发行版中会出错;如果不用这个命令,可以直接安装到其默认的/usr/local/lib目录中


    make
    编译


    make install
    安装


    这样就安装好了。


    [ 本帖最后由 qaarchitech 于 2008-8-1 20:58 编辑 ]
  • [论坛] jmeter资源监控器开发——my sharing

    2008-07-31 22:54:31

    by jack
    You'll get it because of your sharing.

    我修改的源码,解压缩后覆盖原有源码中的src目录,重新编译就可以用了;对编译有疑问的可参见我的帖子http://bbs.51testing.com/thread-121772-1-1.html

    src.rar
    (2008-07-31 22:33:51, Size: 1.59 MB, Downloads: 0)



    监控的xml

    status.rar
    (2008-07-31 22:33:51, Size: 342 B , Downloads: 1)



    编译好的包,象征性收取一点点数 ,希望大家还是自己尝试改一下编译一下,这样今后可以比较容易的扩展出自己想要的监控
    下载编译好的包,把包里的两个jar包拷贝到jmeter的lib\ext目录下,覆盖原来的jar,重启启动jmeter,就可以使用我写的监控器了

    ext.rar
    (2008-07-31 22:33:51, Size: 755 kB, Downloads: 0)



    目前还在写一个shell,用于生成linux下性能数据的符合上面格式的xml,写好后也会分享出来

    [ 本帖最后由 qaarchitech 于 2008-7-31 22:38 编辑 ]
  • [论坛] jmeter资源监控器开发——增加监控数据

    2008-07-31 22:14:50

    by jack

        jmeter自带的监控器输出的只有四条曲线,其中health和load曲线还是根据mem和thread算出来的,所以真正意义上输出的数据只有两个而已。显然这远远满足不了我们对性能监控的需要么。

        既然jmeter没有,那我就有用武之地了(要不然要我这QA架构师干啥,哈),于是我自己添了几个,用着还不错,现在把添加一个参数的过程完整叙述如下:

    以增加swapout为例,取xml中的currentThreadsBusy作为swapout的值。

    蓝色字注明关键点:

    Stats.java

    增加新的数据解析方法

     

           public static int calculateSwapout(Status stat) {

                  double swapout = 0;

                  if (stat != null && stat.getConnector().size() > 0) {

                         Connector cntr = (Connector) stat.getConnector().get(0);

                         swapout = cntr.getRequestInfo().getCurrentThreadsBusy();

                  }

                  return (int) swapout;

           }

     

    MonitorStats.java

    增加私有静态变量

     

           private static final String SWAPOUT = "stats.swapout";

     

    增加构造函数入参、赋值语句

     

           public MonitorStats(int health, int load, int cpuload, int memload, int threadload, int swapin, int swapout, String host, String port,

                         String protocol, long time) {

                  this.setHealth(health);

                  this.setLoad(load);

                  this.setCpuLoad(cpuload);

                  this.setMemLoad(memload);

                  this.setThreadLoad(threadload);

                  this.setSwapin(swapin);

                  this.setSwapout(swapout);

                  this.setHost(host);

                  this.setPort(port);

                  this.setProtocol(protocol);

                  this.setTimeStamp(time);

           }

     

    增加相应setget方法

     

           public void setSwapout(int load) {

                  this.setProperty(SWAPOUT, String.valueOf(load));

           }

     

           public int getSwapout() {

                  return this.getPropertyAsInt(SWAPOUT);

           }

     

    MonitorModel.java

    增加私有变量对象current初始化中MonitorStats实例化的入参

     

           private MonitorStats current = new MonitorStats(0, 0, 0, 0, 0, 0, 0, "", "", "", System.currentTimeMillis());

     

    增加clearData方法中MonitorStats实例化的入参

     

                  current = new MonitorStats(0, 0, 0, 0, 0, 0, 0, "", "", "", System.currentTimeMillis());

     

    增加相应get方法

     

           public int getSwapout() {

                  return this.current.getSwapout();

           }

     

    增加cloneMonitorStats方法的入参

     

           public MonitorStats cloneMonitorStats() {

                  return new MonitorStats(current.getHealth(), current.getLoad(), current.getCpuLoad(), current.getMemLoad(),

                                current.getThreadLoad(), current.getSwapin(), current.getSwapout(), current.getHost(), current.getPort(), current.getProtocol(), current

                                              .getTimeStamp());

           }

     

    MemoryBenchmark.java

    增加main方法中MonitorStats实例化的入参

     

                                MonitorStats mstats = new MonitorStats(Stats.calculateHealth(st), Stats.calculateLoad(st), Stats.calculateCpuLoad(st), Stats

                                              .calculateMemLoad(st), Stats.calculateThreadLoad(st), Stats.calculateSwapin(st), Stats.calculateSwapout(st), "localhost", "8080", "http", System

                                              .currentTimeMillis());

     

    MonitorAccumModel.java

    增加addSample方法中MonitorStats实例化的入参

     

                                   MonitorStats stat = new MonitorStats(Stats.calculateHealth(st), Stats.calculateLoad(st), Stats.calculateCpuLoad(st), Stats

                                                 .calculateMemLoad(st), Stats.calculateThreadLoad(st), Stats.calculateSwapin(st), Stats.calculateSwapout(st), surl.getHost(), String.valueOf(surl

                                                 .getPort()), surl.getProtocol(), System.currentTimeMillis());

     

    增加createNewMonitorModel方法中MonitorStats实例化的入参

     

                  MonitorStats stat = new MonitorStats(Stats.DEAD, 0, 0, 0, 0, 0, 0, url.getHost(), String.valueOf(url.getPort()), url

                                .getProtocol(), System.currentTimeMillis());

     

    MonitorPerformancePanel.java

    增加公共静态变量(显示文案和图例,同时增加资源文件中对应项,及相应图片)

     

           public static final String LEGEND_SWAPOUT = JMeterUtils.getResString("monitor_legend_swapout_per");

     

           public static final ImageIcon LEGEND_SWAPOUT_ICON = JMeterUtils.getImage("monitor-yellow-legend.gif");

     

     

    资源文件messages.properties

    monitor_legend_swapout_per=Swap Out

     

    图片文件monitor-yellow-legend.gif

     

    增加createLegend方法中的JLabel实例化语句

     

                  JLabel jswapout = new JLabel(LEGEND_SWAPOUT);

                  jswapout.setFont(plaintext);

                  jswapout.setPreferredSize(lsize);

                  jswapout.setIcon(LEGEND_SWAPOUT_ICON);

                  legend.add(jswapout);

     

    MonitorGraph.java

    增加私有变量

     

           private boolean SWAPOUT = true;

     

    增加相应set方法

     

           public void setSwapout(boolean swapout) {

                  this.SWAPOUT = swapout;

           }

     

    增加drawSample方法中相应绘图语句

     

                  if (SWAPOUT) {

                         int swoy = (int) (height - (height * (model.getSwapout() / 10000.0)));

                         int lastswoy = (int) (height - (height * (last.getSwapout() / 10000.0)));

     

                         g.setColor(Color.yellow);

                         g.drawLine(lastx, lastswoy, xaxis, swoy);

                  }

     

     

1563/8<12345678>
Open Toolbar