淘宝商城(天猫)高级技术专家.3年研发+3年性能测试调优/系统测试+4年团队管理与测试架构、研发系统实践. 新舞台新气象, 深化测试基础架构及研发架构,希望能在某个技术领域成为真正的技术大牛。欢迎荐才http://bbs.51testing.com/viewthread.php?tid=120496&extra=&page=1 .邮件: jianzhao.liangjz@alibaba-inc.com,MSN:liangjianzhao@163.com.微博:http://t.sina.com.cn/1674816524

发布新日志

  • 应用maven/hudson实施jmeter性能自动化2

    2010-05-22 01:48:57

     

    1.1       部署hudson插件以及配置

     

    参考:http://www.theserverlabs.com/blog/2009/04/23/performance-tests-with-jmeter-maven-and-hudson/

     

    下载http://wiki.hudson-ci.org/display/HUDSON/Performance+Plugin 插件,取代jmeter插件。

           配置好maven 目标,post-build处,勾选:

    Archive the artifacts: jmeter-result/*.html  这里是发布html格式报告。

    Publish performance test result report: google_search*.xml。这里将解析jmeter原始的xml响应数据。

     

     

    1.2       生成结果

     

    执行立即生成,将产生归档的html信息及 详细的请求信息、趋势图等。

     

                如上建立在hudson成功部署的基础上。


    1.3       Jmeter java sampler额外处理

     

    google code下载的附件:jmeter-support-jars-1.0\jmeter-2.3.jar已经涵盖jmeter2.32目录lib/ext/ApacheJMeter_java.jar, ApacheJMeter_core.jar的类。

     

    maven-jmeter-plugin-1.0.jar 没可自定义classpath的属性点。 最简单的办法是把所有依赖到的CLASS加入到环境变量CLASSPATH内。

     

    执行时无需copy实现java smaplerjar jmeter/ lib/ext/目录下。

    优雅的实现,参考:http://my.opera.com/mateamargo/blog/2007/09/27/running-junitsampler-with-maven

    去改写http://jmeter-maven-plugin.googlecode.com/svn/trunk/ 原理是动态调用 URLClassLoader. addURL将路径加入CLASSPATH变量。

    可以用mvn install 安装部署入本地库,也可参考google做法手工加载。

     

      (字数超长了:),分2节发布。

     

     

  • 应用maven/hudson实施jmeter性能自动化

    2010-05-22 01:35:45

    参考

    http://code.google.com/p/jmeter-maven-plugin/wiki/HOWTOUsePlugin

     

     

    从如上url下载maven plugindepenent 先按原文细致执行。

    mvn deploy:deploy-file -DgroupId=org.apache.jmeter -DartifactId=jmeter -Dversion=2.3 -Dpackaging=jar -Dfile=jmeter-2.3.jar -DpomFile=jmeter-2.3.pom -Durl=file://<repo dir>

     

    如上命令是把jar 部署到本地maven reposity库。我个人机器repo dir: "C:\Documents and Settings\jianzhao.liangjz\.m2\repository"

    命令行实际执行如下:

    mvn deploy:deploy-file -DgroupId=org.apache.jmeter -DartifactId=jmeter -Dversion=2.3 -Dpackaging=jar -Dfile=jmeter-2.3.jar -DpomFile=jmeter-2.3.pom -Durl=file://"C:\Documents and Settings\jianzhao.liangjz\.m2\repository"

     

      按原文配置后,对maven工程实施  Mvn clean install 出现多个错误,控制台上错误提示可能误导人。

    在工程目录: target/jmeter/jmeter.log提供真正价值的异常信息。如:

    jmeter.save.SaveService: Conversion error com.thoughtworks.xstream.converters.ConversionException: org/apache/commons/logging/LogFactory : org/apache/commons/logging/LogFactory

     

    源代码可参考:http://jmeter-maven-plugin.googlecode.com/svn/trunk/src/main/java/org/apache/jmeter/JMeterMojo.java

     

     调整细节如下:

           

    1.0       前提部署好maven/jmeter环境

    D:\src\netty_websocket>mvn -version

    Apache Maven 2.2.1 (r801777; 2009-08-07 03:16:01+0800)

    Java version: 1.6.0_11

    Java home: D:\devtools\jdk1.6.0_11\jre

    Default locale: zh_CN, platform. encoding: GBK

    OS name: "windows xp" version: "5.1" arch: "x86" Family: "windows"

     

    D:\src\netty_websocket>  jmeter -v

    Copyright (c) 1998-2008 The Apache Software Foundation

    Version 2.3.2 r665936

     

    1.1        增加Pom.xml 依赖

    <dependency>

                          <groupId>commons-logging</groupId>

                            <artifactId>commons-logging</artifactId>

                            <version>1.0.4</version>

         </dependency>

        

       <dependency>

          <groupId>logkit</groupId>

                    <artifactId>logkit</artifactId>

                    <version>1.2</version>

        </dependency>

     

                  <dependency>

                           <groupId>org.apache.jmeter</groupId>

                           <artifactId>maven-jmeter-plugin</artifactId>

                           <version>1.0</version>

                  </dependency>

          

    1.2       Maven mvn.bat调整

    Maven工程bin/Mvn.bat 运行参数增加CLASSPATH指示器。

     

    %MAVEN_JAVA_EXE% %MAVEN_OPTS% -classpath %CLASSWORLDS_JAR%;"C:\Documents and Settings\jianzhao.liangjz\.m2\repository\commons-logging\commons-logging\1.0.4\commons-logging-1.0.4.jar";"C:\Documents and Settings\jianzhao.liangjz\.m2\repository\logkit\logkit\1.0.1\logkit-1.0.1.jar"  "-Dclassworlds.conf=%M2_HOME%\bin\m2.conf" "-Dmaven.home=%M2_HOME%" org.codehaus.classworlds.Launcher %MAVEN_CMD_LINE_ARGS%

     

    1.3       拷贝upgrade.properties 到工程bin/目录下

    拷贝jmeter/bin下文件upgrade.properties 到如 D:\src\netty_websocket\bin 目录下

    1.4       创建一个jmx文件

    badboy录制google 搜索过程,另存jmeter文件为google_search.jmx

    放到D:\src\netty_websocket\src\test\jmeter 目录下

    1.5       执行命令生成XML报告

    可以mvn jmeter:jmeter,也可 mvn verify

     

    结果文件在D:\src\netty_websocket\target\jmeter-reports\ google_search*.xml

     

    1.6       生成html报告(可选)

    参考 http://jlorenzen.blogspot.com/2008/03/a

    Automated Performance Tests using JMeter and Maven

     

    ·  Under your project create the directory: src/test/jmeter and src/test/resources

    ·  Copy the jmeter.properties file from the JMeter bin folder to src/test/jmeter.

    ·  Update the property jmeter.save.saveservice.output_format in the jmeter.properties file from csv to xml.

    ·  Copy the files jmeter-results-detail-report_21.xsl and jmeter-results-report_21.xsl from the JMeter extras folder to src/test/resources

    .  pom.xml add

     

    <plugin>
                   <groupId>org.codehaus.mojo</groupId>
                   <artifactId>xml-maven-plugin</artifactId>
                   <version>1.0-beta-2</version>
                   <executions>
                       <execution>
                       <phase>pre-site</phase>
                       <goals>
                           <goal>transform</goal>
                       </goals>
                       </execution>
                   </executions>
                   <configuration>
                       <transformationSets>
                           <transformationSet>
                               <dir>${project.build.directory}/jmeter-reports</dir>
                               <stylesheet>src/test/resources/jmeter-results-detail-report_21.xsl</stylesheet>
                               <outputDir>${project.build.directory}/site/jmeter-results</outputDir>
                               <fileMappers>
                                   <fileMapper implementation="org.codehaus.plexus.components.io.filemappers.FileExtensionMapper">
                                       <targetExtension>html</targetExtension>
                                   </fileMapper>
                               </fileMappers>
                           </transformationSet>
                       </transformationSets>
                   </configuration>
               </plugin>  

     

    <>

  • 配置huson执行分布式任务

    2010-05-08 13:12:41

    参考:http://qa.taobao.com/?p=6145

          http://wiki.hudson-ci.org/display/HUDSON/Distributed+builds

     

    默认安装hudson即为master模式,在master部署大量job时,部署slave可提高jobs执行效率。

    Hudson的分布式任务并不需要在slave 上也部署一套hudson环境,而是在建立masterslave之间的连接后master发指令让slave 执行。

     

    试验过程的环境:从http://wiki.hudson-ci.org/display/HUDSON/Cppcheck+Plugin 下载cppcheck.hpi 及源代码,部署好了cppcheck插件。hudson服务器(master)搭建在xen虚拟机上,访问路径:http://192.168.56.101:8080/hudson 任务执行的客户端为windows宿主机。

    1.1.1    建立masterslave 之间连接

    windows上打开浏览器,输入http://192.168.56.101:8080/hudson/computer/

     

    点击新建节点:名称windows_node_cppcheck_parser,选择Dumb Slave

     

    填写必要信息:

    namewindows_node_cppcheck_parser

    Remote fs root: d:/cppcheckxml  -----------------à这里指slave执行任务时,slave 存放被解析文件,包括代码、配置的目录。

    Usage : leave this machine for tied jobs only

    Launch methodlaunch slave agents via jnlp

    点击save配置信息。

     

    点击

    http://192.168.56.101:8080/hudson/computer/windows_node_cppcheck_parser/进入slave连接方式页面。

     

    点击launch图标,可以下载slave.jar包。

    点击launch建立windows机器和 Hudson master连接。

     

    或者在下载 slave.jar的当前目录执行命令建立windows Hudson master的连接:

    java -jar slave.jar -jnlpUrl http://192.168.56.101:8080/hudson/computer/windows_node_cppcheck_parser/slave-agent.jnlp

     

    输入http://192.168.56.101:8080/hudson/computer/windows_node_cppcheck_parser/systemInfo 可以看到windows宿主机环境信息。

     

    再输入http://192.168.56.101:8080/hudson/computer/ 可以看到slave概要信息

    1.1.2    建立与slave关联的jobs

    新建一个Build a free-style. software project  的c 任务。

    http://192.168.56.101:8080/hudson/view/All/job/c/configure

    进入配置页面.

     

    选择 tie this project to a node 绑定到刚才的windows_node_cppcheck_parser节点。

     

     

    选择publish cppcheck results, 输入 *cppcheck*.xml.

    点击立即生成,通过 http://192.168.56.101:8080/hudson/job/c/1/console 看到错误提示:

     

    Parsing has been canceled. No cppcheck test report file(s) were found with the pattern '*cppcheck*.xml' relative to 'd:\cppcheckxml\workspace\c'.

     

    windows宿主机的d:\cppcheckxml\workspace\c 目录放cppcheck源码附带的cppcheck输出内容的testcppcheck1.xml testcppcheck2.xml文件。 再点击立即生成,http://192.168.56.101:8080/hudson/job/c/2/cppcheckResult/可以看到成功解析cppcheck结果。 

    http://192.168.56.101:8080/hudson/job/c/2/console 可看到 Building remotely on windows_node_cppcheck_parser 字样。 

    http://192.168.56.101:8080/hudson/computer/windows_node_cppcheck_parser/ 可以看到slave和项目关联。 

     

    ps:图片偶就不贴了,麻烦

  • 对cppcheck做简单扩展支撑非线程安全函数静态扫描

    2010-04-03 22:49:19

     
      下载 http://sourceforge.net/projects/cppcheck/files/cppcheck/1.42/cppcheck-1.42.tar.gz/download
    1 风格类检查函数放在checkdangerousfunctions.h  checkdangerousfunctions.cpp中
    2 目前只支持gets/scanf/mktemp函数。原来的实现方式为了增加一个非线程安全函数,需要增多>=3个文件
    3 修改头文件checkdangerousfunctions.h

    #define MAX_FUNCS_NUM 200
    #define MAX_FUNC_LEN 48
    extern const char  dangerous_funcs[MAX_FUNCS_NUM][MAX_FUNC_LEN];

    class CheckDangerousFunctions : public Check
    {
    private:
        /** Error Messages.. */
     
     
        void dangerousFunctionnotsafethread(const Token *tok);
     
        bool isDangerousFunction(const Token * tok);

        void getErrorMessages()
        {
           ...
            dangerousFunctionnotsafethread(0);
          ...
        }

    }

    4 实现实现文件checkdangerousfunctions.cpp:

    #include "checkdangerousfunctions.h"
    #include <string.h>
    //---------------------------------------------------------------------------
    const char dangerous_funcs[MAX_FUNCS_NUM][MAX_FUNC_LEN]={"gets (", "asctime (","getc_unlocked (", "getutxid (", "setgrent (", "basename (","getchar_unlocked (", "getutxline (",
        "setkey (", "catgets (" }; //其他更多继续

    ...

    void CheckDangerousFunctions::dangerousFunctions()
    {
        for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
        {
            if( isDangerousFunction(tok))
           {
                dangerousFunctionnotsafethread(tok);
          }
        }
    }
    //---------------------------------------------------------------------------
    bool CheckDangerousFunctions::isDangerousFunction(const Token * tok)
    {
      bool isMatch=false;
      for (int i=0;i <MAX_FUNCS_NUM  &&  ( false !=strcmp(dangerous_funcs[i],"") ) ;i++)
      {
        if (Token::simpleMatch(tok,dangerous_funcs[i]))
        {
           isMatch=true;
           break;
        }
      }
      return isMatch;
    }


    void CheckDangerousFunctions::dangerousFunctionnotsafethread(const Token *tok)
    {
        std::cout<<"token="<< tok->str()<<std::endl;
        std::string funcname="dangerousFunction";
        std::string str_tip="Found \'";
        funcname.append(tok->str());
        str_tip.append(tok->str());
        str_tip.append("\'. You should use ");
        str_tip.append(tok->str());
        str_tip.append("_s instead.for b2bqa");
        const std::string c_func(funcname);
        const std::string c_tip(str_tip);
        reportError(tok, Severity::style, c_func, c_tip);
    }
    ...

    5 应用
    编译
    make;
    执行
    ./cppcheck -s 文件或者目录

    cpplint(http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py)则在扩展方面更好些。


  • selenium 和webdriver_入门实践

    2010-04-01 20:38:01

       我们一直非常强调建立以底层为核心的分层自动化测试体系,虽然web ui自动化在破页、美感方面不值得投入,但是由于目前大量业务逻辑在web ui,所以合适的web ui测试自动比率也是非常关键的。


      watir设计理念和selenium有很大差异。watir便于测试工程师快速上手,对ie支持非常好;而selenium擅长浏览器兼容性。

       参考:

    http://code.google.com/p/meimei/wiki/SeleniumUsage

    http://blog.csdn.net/shendl/archive/2009/03/08/3969750.aspx

    http://blog.csdn.net/shendl/archive/2009/03/08/3969750.aspx

    http://www.ibm.com/developerworks/cn/java/j-lo-selenium/

    http://www.onlymarshall.com/tag/selenium/

    扩展http://xace.javaeye.com/blog/579722

     

    http://code.google.com/p/selenium/downloads/list下载selenium-server-standalone-2.0a2.jar selenium-server-standalone-2.0a2.jar

     

    Webdriver 是对selenium的一个封装,更加友好。Selenium2.0已经把webdriver合并进去。

     执行http://code.google.com/p/selenium/wiki/GettingStarted 代码出错。

    1        webdriver错误:

    Exception in thread "main" org.openqa.selenium.WebDriverException: Cannot find firefox binary in PATH. Make sure firefox is installed.

     解决办法:指定firefox执行文件入系统属性。

         System.setProperty("webdriver.firefox.bin","D:/Program Files/Mozilla Firefox/firefox.exe");

            WebDriver driver = new FirefoxDriver();

           

    2        解决selenium 错误:

     

    下载样例代码http://www.ibm.com/developerworks/cn/java/j-lo-selenium/

    Selenium server需要在java1.5+环境下执行。

    启动selenium server

    java -jar selenium-server-standalone-2.0a2.jar。运行java selenium rc 有错

     

    java.lang.RuntimeException: Could not start Selenium session: Failed to start new browser session: java.lang.RuntimeException: Firefox 3 could not be found in the path!

    Please add the directory containing ''firefox.exe'' to your PATH environment

    variable, or explicitly specify a path to Firefox 3 like this:

    *firefox3c:\blah\firefox.exe

     

      解决办法:指定firefox执行文件路径。

            selenium = new DefaultSelenium("localhost", 4444, "*firefox3 D:/Program Files/Mozilla Firefox/firefox.exe",

                    "http://www.baidu.com");

     

  • 基于规则的svn diff分析结果差异提升code review效率思路

    2010-03-16 21:25:31

       在某些类型的项目中,比如增强安全、更换底层api的项目,修改涉及大量文件,有较多的更改都是相对机械、有规律的。

     如果能够将不符合特定正则表达式的差异结果梳理出,作为重点code review的内容,将提升code review效率。

     甚至更勇敢点,扫描源码文件发现符合规则的行直接更换为新行,该部份代码编写工作都省却了。

     自动化比较的动作本质是对如下几个操作做封装.

    1) 列举svn url下所有的文件

       [liangjz@b2b_plat_1367 cnmarket_bops_security_dev]$ svn list  http://svn/repos/ali_cn/bops/ezra/branches/20100222_cnmarket_bops_security_dev/bops-deploy/templates/topic/screen

    sTTopic.vm

    ...

    2) 对每个文件都获取修订记录

    [liangjz@b2b_plat_1367 cnmarket_bops_security_dev]$ svn log http://svn/repos/ali_cn/bops/ezra/branches/20100222_cnmarket_bops_security_dev/bops-deploy/templates/topic/screen/sTTopic.vm  --stop-on-copy
    ------------------------------------------------------------------------
    r193523 | wb_chao.qian | 2010-02-26 09:15:44 +0800 (??, 2010-02-26) | 1 DD
    r192077 | bruce.fany | 2010-02-22 12:55:08 +0800 (ò?, 2010-02-22) | 1 DD

    3) 比较基线及最新的修订记录

    [liangjz@b2b_plat_1367 cnmarket_bops_security_dev]$ svn diff -r 192077:193523  http://svn/repos/ali_cn/bops/ezra/branches/20100222_cnmarket_bops_security_dev/bops-deploy/templates/topic/screen/sTTopic.vm
    Index: sTTopic.vm
    ===================================================================
    --- sTTopic.vm  (°?±? 192077)
    +++ sTTopic.vm  (°?±? 193523)
    @@ -214,6 +214,7 @@
                    <input type="hidden" name="picname" value="" />
    +                     $xyz.hiddenField
             <tr>
                            <td colspan="6" class="f10"><strong>?ù±?D??¢</strong></td>

     我们需要对+或者-开头的差异内容做大量的字符操作分析。这个是难度最大的,思路一般是结合正则表达式及字符串回溯、前移。

     自动化svn操作用java实现的话,有2种方式

    1) 借用svnkit 包。不需要svn 客户端

    2) 采用java Runtime.exec() api直接执行svn 客户端命令,需要依赖svn 客户端

     上述机械操作应用的范围窄,但是较大减少人肉操作:)

     

  • 建立低成本的代码质量度量体系

    2009-12-11 18:19:36

     

      拟把静态分析数据、可测性度量数据、依赖关系、代码复杂度等维度捏合成一个指标,冒烟测试前扫描完成。以后每次产品测试准入时不断提高指标值。

     

    同时把项目完成后把每千行代码发现的缺陷个数及严重等级、生产环境上发现的故障分,甚至单元测试代码覆盖率、项目持续集成成功率等数据捏合成一个指标。

     

    针对测试准入时度量系数,java工程已有部份开源工具:

    1)静态分析:findbugs

    2) 可测性度量:testability explorer

    3) 依赖关系:jdepend

    4) 代码复杂度:javancss

    5) 代码行统计:sloccount

    6)代码覆盖率:emma/cobertura

     

    linux c++工程相应开源工具:

    1) 静态分析:cppcheck

    2) 代码复杂度:cccc

    3) 代码行统计:sloccount

    4) 代码覆盖率:gcov/lcov

     

     

    但上述工具输出并不一致,为了获得一个更有价值的指标,需要对工具做二次开发。

     

    对于项目测试完成后的几个指标,每千行代码发现缺陷、生产环境故障分可手工录入,单元测试代码覆盖率及持续集成数据可考虑用自动化方式录入。

     

    以上2个指标整合入现有web平台形成portal 以观察代码质量指标变化趋势。

     

  • google开源工具列表(与测试相关)

    2009-11-26 00:15:25

  • 开源多语言代码分析插件框架YASCA

    2009-11-09 00:53:34

     

    参考http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis

     

    本质上yasca是一个开源静态代码分析工具插件框架, 集成流行的多语言静态分析工具如findbugs/pmd/jlint/rats/cppcheck, 由于插件本身多样故可支持java ,c++等语言静态分析.

     

    从 http://sourceforge.net/projects/yasca/files/ 下载yasca-2.1.zip以及其插件的压缩包.

     

    解压yasca-2.1.zip放到 D:\tools\yasca-2.1, 各个插件解压到当前目录. 更详细的目录布局可见D:\tools\yasca-2.1\install.txt文件.

     

    执行yasca自带的样例输出非php文件level=1的报告

     

    D:\tools\yasca-2.1>yasca  -i php -l 1   resources/test/

    Yasca 2.1 - http://www.yasca.org/ - Michael V. Scovetta

    Commercial support is now available for Yasca. Contact scovetta@users.sourceforge.net for more information.

     

    Initializing components...

    Using Static Analyzers located at [d:\tools\yasca-2.1\]

     

     

     Starting scan. This may take a few minutes to complete...

    Forking external process (antiC)...

    External process completed...

    Plugin "ClamAV" not installed. Download it at yasca.org.

    Plugin "cppcheck" not installed. Download it at yasca.org.

    Forking external process (FindBugs)...

    External process completed...

    Forking external process (FxCop)...

    [E_WARNING] [ D:\tools\yasca-2.1\plugins\FxCop.php:68 ] DOMDocument::loadXML(): Start tag expected, '<' not fo

    und in Entity, line: 1

    FxCop did not return a valid XML document. Ignoring.

    Plugin "javascriptlint" not installed. Download it at yasca.org.

    Forking external process (JLint)...

    External process completed...

    Forking external process (PMD) for ./plugins/default/pmd/yasca-rules.xml...

    External process completed...

    Forking external process (PMD) for ./plugins/default/pmd/yasca.xml...

    External process completed...

    Forking external process (RATS)...

    [E_WARNING] [ D:\tools\yasca-2.1\plugins\Rats.php:51 ] DOMDocument::loadXML(): Empty string supplied as input

    RATS did not return a valid XML document. Ignoring.

    Creating report...

    Results have been written to C:\DOCUME~1\JIANZH~1.LIA\LOCALS~1\Temp\Yasca-Report-20091108110623.html

     

    以上可以看到采用JLint,PMD,RATS分析代码. 比较遗憾rats出现windows异常.

     

    检查结果可看到检测到SQL Injection, Cross-Site Scripting, Code Quality: Functions, Authentication价值较高的建议

     

  • 持续集成开展的必需条件

    2009-08-11 22:12:57

       根据当下在产品型测试实践梳理的几点想法:

    一 人才

    a 配管

    懂常用持续集成服务器,如cruisecontrol/continuum, buildbot 等原理及安装配置.
    另外,需要了解java 编译,c++ makefile,subversion等配置管理知识.

    b 研发/QA:  合格的. 最最重要的是有良好的质量意识及实践能力.

    c 主管/经理:
     
     他们是有力后盾,当涉及资源及机制时,是一锤定音者.
     
    二 技术

    最核心的是良好的单元测试编码, 集成测试编码,系统测试编码, web ui层自动化等不同level的自动化能力.

    为了确保单元测试代码有效性,可以考虑:

    1) 对单元测试代码做code review
    2) 研发交叉编写单元测试代码
    3) QA参与单元测试设计 或者编写单元测试代码

    研发编码水平,QA测试开发能力都应该在一个较高水位.

    三机制

     实践中,这个也是影响面最大的, 没有好的机制粘合,要做好持续集成基本不现实.

    在当下,我面临的问题:

    1)     源代码规范及makefile规范,  避免硬编码以满足buildbot需求

    2)     统一c++单元测试框架. 

    3)     统一单元测试输出结果

    4)     单元测试代码编写方面做更多摸索( 研发交叉编写单元测试?QA前期介入单元测试设计?...).    涉及到资源计划

    5)     集成测试方面的探索, 减少外部依赖

    6)      对buildbot /continuum 结果的快速响应以及相关的约定 ( 进入集成测试后,build 失败次数<n 以及每次build修复时间<n小时)

    7)     研发提交QA的标准, >50%代码覆盖率应在持续集成后一直保持并且经过有效review

    8)     项目退出标准细化 ( 需要保证连续n天0个高优先级bug 并且持续集成连续成功n天以上)

    9)...


    四 设备

    用钱能解决的问题最容易解决.^_^

    当同时做持续集成时,需要确保编译,运行测试验证,发送报告时间不要太长.

     

  • 应用Buildbot实施c++持续集成

    2009-07-15 01:33:39

    参考: 

    http://perl-qa.hexten.net/wiki/index.php/Buildbot

    http://blog.chinaunix.net/u2/68938/showart_1076484.html

    http://blog.csdn.net/yurenjimi/archive/2008/12/01/3413829.aspx

    http://www.lothar.com/repos/buildbot-website/manual-0.7.5.html#Compile

     

     

    buildbot 在阿里大型c++研发项目中已经被证明是高效的持续集成运转的重要一环,正发挥check in build/daily build/daily test重要功效.

     

    buildbot依赖TwistedPython.

    本次的环境(64位的操作系统不支持)

    Python 2.5.2

    Linux b2b_plat_1367 2.6.9-42.ELsmp #1 SMP Wed Jul 12 23:27:17 EDT 2006 i686 i686 i386 GNU/Linux

     

     

    为了邮件提醒,需要先安装sendmail 并且配置成功

    [root@b2b_plat_1367 ~]# rpm -qa |grep sendmail

    sendmail-8.13.1-3.RHEL4.5

    sendmail-cf-8.13.1-3.2.el4

     

     

    1.      下载安装 Twisted

    wget -c http://tmrc.mit.edu/mirror/twisted/Twisted/8.1/Twisted-8.1.0.tar.bz2
     bzip2 -d Twisted-8.1.0.tar.bz2

    tar -xvf Twisted-8.1.0.tar
     cd Twisted-8.1.0

    python setup.py install --prefix=$HOME

        

    Twisted 依赖 zope.interface and Python


    wget   -c
    http://www.zope.org/Products/ZopeInterface/3.3.0/zope.interface-3.3.0.tar.gz

    tar  -zxvf  zope.interface-3.3.0.tar.gz

    cd zope.interface-3.3.0
    python setup.py build
    python setup.py install --prefix=$HOME

    2
     安装 buildbot 0.7.7
    wget -c http://pypi.python.org/packages/source/b/buildbot/buildbot-0.7.7.tar.gz#md5=4647a15a9d9b2db6a5b3493ac78e11d9
    tar -zxvf  buildbot-0.7.7.tar.gz

    cd buildbot-0.7.7
    python setup.py build
    python setup.py install --home=~

    设置环境变量:

    export PYTHONPATH=$HOME/lib/python:/home/liangjz/lib/python2.5/site-packages/

     

     

    3 测试

     [liangjz@b2b_plat_1367 buildbot_master]$ buildbot --version

    Buildbot version: 0.7.7

    Twisted version: 8.1.0

     

    4 生成服务器端配置文件


    mkdir ~/buildbot_master
    buildbot create-master buildbot_master

     

     

    请特别注意大型应用中svn扫描时间及缓冲时间应该设置长些.

    同时确保Makefile 目录结构正确,否则会导致make 进程死循环,导致cpu%高达80%无法响应.

     

    [liangjz@b2b_plat_1367 buildbot_master]$ cat master.cfg | grep -v '#'

     

     

     

     

    c = BuildmasterConfig = {}

     

     

    from buildbot.buildslave import BuildSlave

     

    c['slaves'] = [BuildSlave("bot1name", "bot1passwd")]

     

     

     

    c['slavePortnum'] = 9989

     

     

     

     

    from buildbot.changes.svnpoller import SVNPoller  

    c['change_source'] = SVNPoller("http://svn.alibaba-inc.com/repos/ali_QA/20_Scripts/06_maven_projects",

                        svnuser='myusername', svnpasswd='mypassword', 

                        pollinterval=5)       

     

     

     

     

     

     

     

    from buildbot.scheduler import Scheduler

    c['schedulers'] = []

    c['schedulers'].append(Scheduler(name="all", branch=None,

                                     treeStableTimer=2*60,

                                     builderNames=["buildbot-full"]))

     

     

     

     

     

     

     

    from buildbot.process import factory

    from buildbot.steps.source import SVN

    from buildbot.steps.shell import Compile

    from buildbot.steps.python_twisted import Trial

    from buildbot.steps import source, shell

    from buildbot.steps.shell import ShellCommand, WithProperties

     

     

     

     

     

     

     

     

    f1 = factory.BuildFactory()

    f1.addStep(SVN(mode='update', baseURL='http://svn.alibaba-inc.com/repos/ali_QA/20_Scripts/06_maven_projects',    defaultBranch=''))

    f1.addStep(Compile(command=["make"]))

     

    f1.addStep(ShellCommand, command=["make", "test"])

     

     

    b1 = {'name': "buildbot-full",

          'slavename': "bot1name",

          'builddir': "full",

          'factory': f1,

          }

    c['builders'] = [b1]

     

     

     

     

    c['status'] = []

     

    from buildbot.status import html

    c['status'].append(html.WebStatus(http_port=8010))

     

     

    from buildbot.status import mail

     

    c['status'].append(mail.MailNotifier(fromaddr="jianzhao.liangjz@alibaba-inc.com",                                    mode="all",                                    extraRecipients=["jianzhao.liangjz@alibaba-inc.com","teson.jinz@alibaba-inc.com"],                                    sendToInterestedUsers=False))

     

     

     

     

     

     

     

     

    c['projectName'] = "Buildbot"

    c['projectURL'] = "http://buildbot.sourceforge.net/"

     

     

    c['buildbotURL'] = http://localhost:8010/

     

     

    启动服务器:

      cd buildbot_master

    buildbot start .

     

     

    5 配置客户端:

     

    buildbot create-slave --umask=022 ~/buildslave b2b_plat_1367:9989     bot1name   bot1passwd

     

     

    buildbot create-slave build_test/ localhost:8010    bot1name   bot1passwd

     

     

    启动客户端:

     

    cd    buildslave

    buildbot start .

     

     

    6 造一个c++小程序

     

     

    [liangjz@b2b_plat_1367 maven_proj]$ cat Makefile

    PUBLIC_PATH=../../

     

    LDPATH=\

            -L.

     

    INCLUDE=\

            -I.

     

     

    CFLAG = -c -g -Wall $(INCLUDE)

    #CFLAG = -c -O3 $(INCLUDE)

     

    GCC = gcc

    .SUFFIXES: .o .cpp

     

    OBJS=run.o

          

     

     

    all: run

     

     

    run:  $(OBJS)

            $(GCC)   -o $@   $(OBJS)

     

    .cpp.o:

            $(GCC) $(CFLAG) -o $@ $<

     

    clean:

            rm  run

            rm  run.o

     

    test:

            `pwd`/run

     

     

     

    更改提交

    Svn ci  Makefile  -m   “test”

     

    代码变更被svnpoll检测到.

     

    7 查看结果:

     

    http://10.20.136.7:8010/waterfall

     

     

    8 检查中间build过程:

     

    [liangjz@b2b_plat_1367 build]$ pwd

    /home/liangjz/buildslave/full/build

    [liangjz@b2b_plat_1367 build]$ ll -al

    total 40

    drwxr-xr-x  4 liangjz liangjz 4096 Jul 11 17:07 .

    drwxr-xr-x  3 liangjz liangjz 4096 Jul 11 17:07 ..

    -rw-r--r--  1 liangjz liangjz   69 Jul 11 17:07 .buildbot-sourcedata

    -rw-r--r--  1 liangjz liangjz  313 Jul 11 17:07 Makefile

    -rwxr-xr-x  1 liangjz liangjz 4685 Jul 11 17:07 run

    -rw-r--r--  1 liangjz liangjz  100 Jul 11 17:07 run.c

    -rw-r--r--  1 liangjz liangjz  880 Jul 11 17:07 run.o

    drwxr-xr-x  6 liangjz liangjz 4096 Jul 11 17:07 simple-webapp

    drwxr-xr-x  6 liangjz liangjz 4096 Jul 11 17:07 .svn

     

     

    9)收取邮件通知:

    The Buildbot has finished a build of buildbot-full on Buildbot.

    Full details are available at:

     http://10.20.136.7:8010/builders/buildbot-full/builds/8

     

    Buildbot URL: http://10.20.136.7:8010/

     

    Buildslave for this Build: bot1name

     

    Build Reason:

    Build Source Stamp: 16520

    Blamelist: liangjz

     

    Build succeeded!

     

    sincerely,

     -The Buildbot

     

     

     

    特别注意事项:

     

    1)      buildslave需要单独测试,确保代码外部依赖库都ok

    2)      makefile需要考虑是放到buildslave/full/build 目录,所以Makefile文件确保无路径依赖

     

    另外,为方便整体项目编译,最好有一个Makefile做总控 类似

     

    [liangjz@b2b_plat_1367 dragoon2.0]$ vi Makefile

     

    all:

            cd depend/framework;make clean;make;cp libframework.a ../../lib/

            cd src/common;make clean;make

            cd src/master;make clean;make

            cd src/monitor;make clean;make

            cd src/agent;make clean;make

            cp /home/liangjz/dragoon2.0/bin/*    /home/liangjz/buildslave/full/build/bin/

     

    3)      make test 同样需要确认外部的文件依赖及目录结构正确

    4)      为了统一发送自定义的邮件,需要c++使用统一的单元测试报告格式.

     

  • 利用easyMock模拟JDBC查询

    2009-01-03 23:40:39

    参考:http://solnone.blogspot.com/search/label/Java

    mock,就是假的意思。easymock或者jmock之类的框架最常用于减少外部重量级资源依赖。

     

    import java.sql.Connection;

    import java.sql.PreparedStatement;

    import java.sql.ResultSet;

    import java.sql.SQLException;

    import java.util.ArrayList;

    import java.util.List;

     

    public class DBImpl {

        public List query(Connection conn) throws SQLException {

           List list = new ArrayList();

           PreparedStatement ps = conn.prepareStatement("select user from user");

           try {

               ResultSet rs = ps.executeQuery();

               try {

                  while (rs.next()) {

                      list.add(rs.getString(1));

                  }

               } finally {

                  rs.close();

               }

           } finally {

               ps.close();

           }

           return list;

        }

    }

     

     

    import static org.easymock.EasyMock.createControl;

    import static org.easymock.EasyMock.expect;

    import static org.easymock.EasyMock.matches;

     

    import static org.junit.Assert.assertEquals;

    import java.sql.Connection;

    import java.sql.PreparedStatement;

    import java.sql.ResultSet;

    import java.sql.SQLException;

    import java.util.Arrays;

    import java.util.List;

    import org.easymock.IMocksControl;

    import org.junit.After;

    import org.junit.Before;

    import org.junit.Test;

     

    public class DBImplTest {

        private DBImpl dbimpl;

     

        @Before

        public void setUp() throws Exception {

           dbimpl = new DBImpl();

        }

     

        @After

        public void tearDown() throws Exception {

           dbimpl = null;

        }

     

        @Test

        public void testQuery() throws SQLException {

           IMocksControl control = createControl();

            // 建立模擬物件

           Connection conn = control.createMock(Connection.class);

           PreparedStatement ps = control.createMock(PreparedStatement.class);

           ResultSet rs = control.createMock(ResultSet.class);

           // 模擬物件預期行為

     

           expect(conn.prepareStatement(matches("select user from user")))

                  .andReturn(ps);

           expect(ps.executeQuery()).andReturn(rs);

           expect(rs.next()).andReturn(true);

           expect(rs.getString(1)).andReturn("root");

           expect(rs.next()).andReturn(true);

           expect(rs.getString(1)).andReturn("tester");

           expect(rs.next()).andReturn(true);

           expect(rs.getString(1)).andReturn("中文");

           expect(rs.next()).andReturn(false);

           rs.close();

           ps.close();

           // 錄製完成,切到 replay 狀態

           control.replay();

           // 調用方法

           List expected = Arrays.asList(new String[]{"root", "tester","中文"});

          

           //这个conn是假的

           List  result = dbimpl.query(conn);

           assertEquals(expected, result);

           // 驗證

           control.verify();

        }

    }

     

     

    CLASSPATH加入easymock.jarcglib-2.2.jar 以及easymockclassextension.jar.

    调试上述程序,dbimpl.query(conn)如期执行真正的查询操作,无须建立真正的数据库联接。

     

     

  • HTTPUnit对部分中文网页JS检测出错的处理方法

    2009-01-01 18:43:36

      2009年第一天第一篇测试相关文档:)

     httpUnit在内部公共框架测试上应用。

     参考:http://www.blogjava.net/relax/archive/2005/01/27/743.html

     

     

    httpunit/jars 目录下jar都加入classpath,否则运行时出错。

     

    wc = new WebConversation();// 初始化httpunit

           try {

               GetMethodWebRequest req = new GetMethodWebRequest(

                  //  "http://www.google.cn/search?h1=zh-CN&q=mp4");

                      "http://www.sina.com.cn");

     

               //HttpUnitOptions.setExceptionsThrownOnscrīptError(false);

               WebResponse rep = wc.getResponse(req);

               assertTrue(true);

               WebLink[] links=rep.getLinks();

               for (int i=0;i < links.length;i++)

               {

                  System.out.println(links[i].getURLString());

               }

              

               WebResponse n_rep=links[4].click();

              

               System.out.println(n_rep.getText());

           } catch (Exception e) {

               e.printStackTrace();

               assertFalse(false);

           }

     

    发请求给www.sina.com.cn异常1

     

    org.mozilla.javascrīpt.EcmaError: TypeError: Cannot call method "toLowerCase" of undefined (httpunit

    at com.meterware.httpunit.javascrīpt.scrīptingEngineImpl.handlescrīptException(scrīptingEngineImpl.java:64)

     

    发请求给www.alibaba.com.cn 异常2

    at com.meterware.httpunit.javascrīpt.scrīptingEngineImpl.handlescrīptException(scrīptingEngineImpl.java:64)

        at com.meterware.httpunit.javascrīpt.scrīptingEngineImpl.runscrīpt(scrīptingEngineImpl.java:95)

     

     

    参考:http://lupingui.javaeye.com/blog/239738 在发送http 请求前增加选项:

    HttpUnitOptions.setExceptionsThrownOnscrīptError(false);

    即解决。

     

  • 阿里巴巴自动化测试发展思路

    2008-11-01 21:39:02

      自动化总体要求是 自动化覆盖率更高,维护成本更低,挖掘层次更深,运行速度更快,培训力度和知识分享覆盖面更大,运营管理更加规范, WATIR框架平稳取代QTP框架

             1)   代码更加灵活。 比如代码可以通过配置数据库检查开关

    2)   由于代码变更,各小组接口人定期(每2个月?)结合代码覆盖率数据,给出各个小组自动化下一步功能自动化用例建议

    3)   人员增长很快,所以培训力度、分级制度更完善。 各个小组接口人注意跟上。 另外,知识分享做好可以大幅度降低学习门槛

    4)   项目发布后预留一些自动化脚本编写时间,以便及时维护、完善脚本,从而减少自动化脚本重复执行次数

    5)   脚本运行速度进一步提升。 从另外一个角度,力争研发单位预留至少一个晚上运行时间以及前一天必要的准备运行时间

    6)   继续完善自动化运行管理平台,自动统计、分析QTP/WATIR框架、脚本运行状况,图形化展现覆盖率数据趋势―――――――――――――――――――――――这个需要额外增强现有框架

    7)   接口人定期跟进项目,挖掘可自动化的点,主要由测试组实施。

    8)   测试小组第一期自动化脚本由QA架构组主导搭建,后期的维护、增强由测试组实施。工作重心在优化框架,解决部门级别公共自动化问题  

    9)   深入接口测试,SOA测试等,不局限于页面级别自动化

  • 分布式计算hadoop部署

    2008-08-22 20:24:35

     

    很多人听说google 的云计算,基础mapreduce、gfs,但都停留于纸面。apache和yahoo 合作有一个类似项目hadoop,国内已经有实际公司在应用,如阿里妈妈,国外有hive项目。

    说这么多,不如实际部署一个体验下。

     

    hadoop要求sun jdk1.5或者以上,linux 平台。


    更多参考 http://www.infoq.com/cn/articles/hadoop-config-tip
    http://www.michael-noll.com/wiki/Running_Hadoop_On_Ubuntu_Linux_(Single-Node_Cluster)#Prerequisites

     

    分布式部署

    参考Hadoop Cluster Setup

     

    2台机器10.0.4.145 (NameNodeJobTracker角色),10.0.4.146(DataNodeTaskTracker的角色)

    都建立同样的目录/home/search/hadoop-0.17.1

     

    在主节点145  [search@b2bsearch145 ~]$ cat .bash_profile

    export HADOOP_HOME=/home/search/hadoop-0.17.1

    export PATH=$PATH:$HADOOP_HOME/bin

     

    方便命令行操作

    1.1    创建证书建立信任登录过程

    建立Master到每一台SlaveSSH受信证书。

     

    确保~/.ssh/authorized_keys 的文件权限为 600

    [search@b2bsearch145 hadoop-0.17.1]$ ll  ~/.ssh/authorized_keys

    -rw-r--r--  1 search search 2529  6 25 10:01 /home/search/.ssh/authorized_keys

    [search@b2bsearch145 hadoop-0.17.1]$ cat ~/.ssh/authorized_keys |grep 146

    ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA7naNGEpcbuon2/4M+0FDRp594MNk7jV0U3SaDLlT4vLvo0viCSP/2mEMi7iadaogkSr3FbIHryUsOhZ1MSwiDc2nv3TgxAh3K/jQkbP1MDGdHzOVvScrWcTfpFhDtL29HQJit5fpST0aZDlbCn8LsYX+y171Pun9Q4HyT9TkUL0= search@alitest146

    ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA06pe9YZTEEqmiutmjWQ1CgnmOWd3xh2YkqDinSuZi7t/Uyg/u/l0vJ5nv196dnYqdJJTyaVUU+ydcS7UJu+ykpeIYZGSL6XC2MqTMCpEVAtqP9WUhFXToJmq0tDrlYTfnYZOCIrDt+hjp+c7E7EH3phtEHdrlaAs9ZvcM/6/4L0= search@intl_search38146

     

    1.2    配置文件

    解压后进入conf目录,主要需要修改以下文件:hadoop-env.shhadoop-site.xmlmastersslaves

     

    默认的hadoop-default.xml 仅仅更改dfs.permissions.supergroup属性值为当前用户组名称。 bash -c groups获取group名称

    <property>

      <name>dfs.permissions.supergroup</name>

      <value>search</value>

      <descrīption>The name of the group of super-users.</descrīption>

    </property>

     

     

    hadoop-env.sh 仅仅更改 JAVA_HOME

     

    # export JAVA_HOME=/usr/lib/j2sdk1.5-sun

    export JAVA_HOME=/usr/ali/jdk1.6

     

     

    一个可用的hadoop-site.xml

     

     

    [search@b2bsearch145 conf]$ vi  hadoop-site.xml

     

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

    <!-- Put site-specific property overrides in this file. -->

    <configuration>

    <property>

    <name>fs.default.name</name>

    <value>hdfs://10.0.4.145:54310/</value></property>

    <property>

    <name>mapred.job.tracker</name>

    <value>hdfs://10.0.4.145:54311/</value>

    </property>

    <property>   <name>dfs.replication</name>

    <value>1</value></property><property>

    <name>hadoop.tmp.dir</name>

    <value>/home/search/hadoop-0.17.1/tmp/</value></property>

    <property>

    <name>mapred.child.java.opts</name>

    <value>-Xmx512m</value></property>

    <property>  <name>dfs.block.size</name>

    <value>5120000</value>  <descrīption>The default block size for new files.</descrīption>

    </property></configuration>

     

    ~                                           

    [search@b2bsearch145 conf]$ cat masters

    10.0.4.145

    [search@b2bsearch145 conf]$ cat slaves

    10.0.4.146

     

     

    1.3    初始化dfs以及启动进程

     

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop  namenode  -format

    08/08/21 19:48:54 INFO dfs.NameNode: STARTUP_MSG:

    /************************************************************

    STARTUP_MSG: Starting NameNode

    STARTUP_MSG:   host = b2bsearch145/10.0.4.145

    STARTUP_MSG:   args = [-format]

    STARTUP_MSG:   version = 0.17.1

    STARTUP_MSG:   build = http://svn.apache.org/repos/asf/hadoop/core/branches/branch-0.17 -r 669344; compiled by 'hadoopqa' on Thu Jun 19 01:18:25 UTC 2008

    ************************************************************/

    08/08/21 19:48:54 INFO fs.FSNamesystem: fsOwner=search,search

    08/08/21 19:48:54 INFO fs.FSNamesystem: supergroup=search

    08/08/21 19:48:54 INFO fs.FSNamesystem: isPermissionEnabled=true

    08/08/21 19:48:54 INFO dfs.Storage: Storage directory /home/search/hadoop-0.17.1/tmp/dfs/name has been successfully formatted.

    08/08/21 19:48:54 INFO dfs.NameNode: SHUTDOWN_MSG:

    /************************************************************

    SHUTDOWN_MSG: Shutting down NameNode at b2bsearch145/10.0.4.145

    ************************************************************/

     

    [search@b2bsearch145 hadoop-0.17.1]$ bin/start-dfs.sh

    starting namenode, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-namenode-b2bsearch145.out

    10.0.4.146: starting datanode, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-datanode-alitest146.out

    10.0.4.145: starting secondarynamenode, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-secondarynamenode-b2bsearch145.out

    [search@b2bsearch145 hadoop-0.17.1]$ bin/start-mapred.sh

    starting jobtracker, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-jobtracker-b2bsearch145.out

     

    10.0.4.146: starting tasktracker, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-tasktracker-alitest146.out

     

    [search@b2bsearch145 hadoop-0.17.1]$ /usr/ali/jdk1.6/bin/jps

    18390 NameNode

    18589 JobTracker

    18721 Jps

    18521 SecondaryNameNode

     

     

    1.4    执行分布式统计词

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs -copyFromLocal  input/  test-in

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -ls

    Found 1 items

    /user/search/test-in    <dir>           2008-08-21 19:53        rwxr-xr-x       search  search

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -ls /user/search/test-in

    Found 2 items

    /user/search/test-in/hadoop-default.xml <r 1>   37978   2008-08-21 19:53        rw-r--r--       search  search

    /user/search/test-in/hadoop-site.xml    <r 1>   178     2008-08-21 19:53        rw-r--r--       search  search

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -cat  /user/search/test-in/hadoop-default.xml

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

     

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop jar hadoop-0.17.1-examples.jar wordcount  /user/search/test-in  test-out

    08/08/21 19:55:45 INFO mapred.FileInputFormat: Total input paths to process : 2

    08/08/21 19:55:46 INFO mapred.JobClient: Running job: job_200808211951_0001

    08/08/21 19:55:47 INFO mapred.JobClient:  map 0% reduce 0%

    08/08/21 19:55:52 INFO mapred.JobClient:  map 66% reduce 0%

    08/08/21 19:55:54 INFO mapred.JobClient:  map 100% reduce 0%

    08/08/21 19:56:01 INFO mapred.JobClient:  map 100% reduce 100%

    08/08/21 19:56:02 INFO mapred.JobClient: Job complete: job_200808211951_0001

    08/08/21 19:56:02 INFO mapred.JobClient: Counters: 16

    08/08/21 19:56:02 INFO mapred.JobClient:   File Systems

    08/08/21 19:56:02 INFO mapred.JobClient:     Local bytes read=36202

    08/08/21 19:56:02 INFO mapred.JobClient:     Local bytes written=72658

    08/08/21 19:56:02 INFO mapred.JobClient:     HDFS bytes read=39559

    08/08/21 19:56:02 INFO mapred.JobClient:     HDFS bytes written=19133

    08/08/21 19:56:02 INFO mapred.JobClient:   Job Counters

    08/08/21 19:56:02 INFO mapred.JobClient:     Launched map tasks=3

    08/08/21 19:56:02 INFO mapred.JobClient:     Launched reduce tasks=1

    08/08/21 19:56:02 INFO mapred.JobClient:     Data-local map tasks=3

    08/08/21 19:56:02 INFO mapred.JobClient:   Map-Reduce Framework

    08/08/21 19:56:02 INFO mapred.JobClient:     Map input records=1239

    08/08/21 19:56:02 INFO mapred.JobClient:     Map output records=3888

    08/08/21 19:56:02 INFO mapred.JobClient:     Map input bytes=38156

    08/08/21 19:56:02 INFO mapred.JobClient:     Map output bytes=51308

    08/08/21 19:56:02 INFO mapred.JobClient:     Combine input records=3888

    08/08/21 19:56:02 INFO mapred.JobClient:     Combine output records=1428

    08/08/21 19:56:02 INFO mapred.JobClient:     Reduce input groups=1211

    08/08/21 19:56:02 INFO mapred.JobClient:     Reduce input records=1428

    08/08/21 19:56:02 INFO mapred.JobClient:     Reduce output records=1211

     

    1.5    观察结果

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -ls   /user/search/test-out 

    Found 2 items

    /user/search/test-out/_logs     <dir>           2008-08-21 19:55        rwxr-xr-x       search  search

    /user/search/test-out/part-00000        <r 1>   19133   2008-08-21 19:55        rw-r--r--       search  search

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -cat  /user/search/test-out/part-00000 |more

    "_logs/history/"        1

    "all".</descrīption>    1

    "block"(trace   1

    "dir"(trac      1

    "false",        1

    "local",        1

     

    更多命令参考:Hadoop Shell Commands

     

     

    1.6    Web UI 浏览NameNode

     

     

    1.7    Web UI 浏览DataNode

     

     

     

    1.8    WEB UI浏览JobTracker

     

     

     

    1.9    Web UI 浏览TaskTracker

     

    1.10       停止应用

     

    后续比较有意思的一些使用体验也将陆续上传。

  • [论坛] 如何引入代码覆盖率度量提高测试质量

    2008-07-12 13:44:31

    我们面临的困境
    1) 开发编写的单元测试代码可信度
    2) 功能测试或者自动化测试效果可信度

    为了提高测试过程的质量,是一个复杂系统过程。国外好些年前就引入代码覆盖率工具,比如
    EMMA/Clover。
    呵呵,据了解ebay中国的开发采用EclEmma。

    经过初步评估,针对java语言的EMMA 和针对 linux+ c/c++ +gcc的gcov/lcov都只能做到语句覆盖、函

    数覆盖、类覆盖。对于路径覆盖、条件覆盖等无法做。要做到更加精细,可以考虑结合Jester。

    代码覆盖率工具最让人震撼的是,无须单元测试代码,可以清楚看到执行过/未执行过的代码行,以及由

    宏观到微观的度量结果。另外引入代码覆盖率工具,无须修改代码,成本极低。

    这个结果对于开发而言,可以增加自己负责的模块的单元测试代码,或者去除死代码。
    对于测试而言,可以增加测试用例提高覆盖率,提高测试结果的信心度。

    尽管代码覆盖率工具有这样或者那样的不足,也极难做到100%覆盖,但综合权衡,引入工具还是有积极

    的意义。

    推广代码覆盖率的规划:

    1) 选取一个小型WEB应用代码覆盖工具,结果供测试工程师,分析代码覆盖率效益
    2) 大型项目应用代码覆盖工具
    3) 在研发部门推广EclEmma插件 和gcov/lcov
    4) 经过一段时间实践,在开发提交代码给测试时,要求一起提交代码覆盖率源文件。

    难点:

    1) 测试工程师面对未覆盖的代码行,要有阅读代码能力呼应到业务操作,以有针对性增加测试用例
    1) 加入代码覆盖率结果,意味对上游输出把握更加严格,要求研发部门经理和开发的意识转变以及实质

    性支持

    欢迎这方面有实践的朋友多提建议,谢谢
  • [论坛] 采用EMMA对JMeter执行代码覆盖率分析

    2008-07-12 12:19:01

    emma度量代码覆盖率不需要额外编写单元测试代码。
    支持JAVA GUI、JAVA CONSOLE、JAVA APP SERVER。

    一 安装与配置
    EMMA支持jdk1.2 或以上。

    下载: http://emma.sourceforge.net/
    在我的电脑里面设置CLASSPATH加入emma.jar.
    显示:
    E:\jakarta-jmeter-2.3.1\bin>echo %CLASSPATH%
    E:\alibaba\tools\emma-stable-2.1-lib\emma.jar;.


    二 收集应用的元信息

    这一步必须有.class文件或者包含.class文件的jar包。
    而且必须在应用执行的目录下进行(非源代码的路径),否则第四步收集信息时出现异常"emma ctl:

    coverage.get: RPC failure while executing [coverage.get]
    Exception in thread "main" com.vladium.emma.EMMARuntimeException: coverage.get:
    RPC failure while executing [coverage.get]
            at com.vladium.emma.ctl.CtlProcessor._run(CtlProcessor.java:242)"



    收集元信息(会改写ApacheJmeter.jar内容)
    java emma instr -m overwrite   -cp  ApacheJMeter.jar  -out coverage.em

    正常时当前目录生成coverage.em。

    三 执行应用程序

    jmeter.bat导致异常
    Exception in thread "main" java.lang.NoClassDefFoundError: com/vladium/emma/rt/R
    T
            at org.apache.jmeter.NewDriver.$VRi(NewDriver.java)
            at org.apache.jmeter.NewDriver.<clinit>(NewDriver.java)
    errorlevel=1

    分析确认由于java加载ApacheJMeter.jar包时ClassLoader顺序非预期,通过-

    Xbootclasspath/p:E:\alibaba\tools\emma-stable-2.1-lib\emma.jar  强制优先加载emma.jar。

    故修改jmeter.bat为
    %JM_START% %JM_LAUNCH%  -Xbootclasspath/p:E:\alibaba\tools\emma-stable-2.1-lib\emma.jar  %

    JVM_ARGS% %ARGS%   -jar "%JMETER_BIN%ApacheJMeter.jar" %JMETER_CMD_LINE_ARGS%

    再次启动jmeter.bat,出现提示

    EMMA: collecting runtime coverage data ...
    EMMA: runtime controller started on port [47653]

    netstat 检查47653端口处于Listening状态。

    在JMeter界面上操作。后台会记录代码执行状况

    四 收集代码行、函数、类覆盖信息

    在Jmeter不退出的情况下,执行
    java -cp %CLASSPATH%  emma ctl -connect localhost:47653 -command coverage.get,coverage.ec

    或者Jmeter正常退出的情况下,也会主动收集信息存放在默认的coverage.ec。

    五  生成报告

    java -cp %CLASSPATH%   emma report -r html -in  coverage.em,coverage.ec -

    Dreport.html.out.file=coverage.html -Dreport.metrics=class:50
  • 解决 perl xml getNodeValue 为空值的过程

    2008-04-19 22:37:48

    记录一下,不熟悉Perl xml 处理过程,吃了大亏:)

     

    http://www.51testing.com/?170805/action_viewspace_itemid_80386.html

     

  • [论坛] 请问有vbscript 和qtp profiler 的工具么

    2008-03-12 20:51:55

    我们知道c或者java 分别由  gprof,purify 工具。

    有vbscript 和qtp 代码profiler 的工具么?  以便我们更清晰地优化代码 
Open Toolbar