日历

« 2008-09-08  
 123456
78910111213
14151617181920
21222324252627
282930    

统计信息

  • 访问量: 11347
  • 日志数: 104
  • 图片数: 1
  • 建立时间: 2007-03-16
  • 更新时间: 2008-09-06

RSS订阅

成长在电信,发展在阿里巴巴。深化性能测试、自动化测试、搜索引擎测试领域,希望能在某个技术领域成为真正的技术大牛。欢迎荐才 http://bbs.51testing.com/viewthread.php?tid=103451&highlight=%B0%A2%C0%EF%B0%CD%B0%CD 。 邮件: jianzhao.liangjz@alibaba-inc.com

我的最新日志

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

    2008-9-06

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

    主要的技术为: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 找了一些特效嵌入。

  • spring + velocity实现分页程序2

    2008-9-01

    接续

    package com.ali;

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.context.ApplicationContext;
    import org.springframework.validation.BindException;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.SimpleFormController;

    import com.ali.db.User;
    import com.ali.util.PageUtil;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    public class UserListController extends SimpleFormController {
     private IIbatisDAO currDAO;
     private String  m_pagesize;
     public UserListController() {
      setCommandClass(UserListForm.class);
     }

     public ModelAndView handleRequestInternal(HttpServletRequest request,
       HttpServletResponse response) throws Exception {
      
      if ( request.getMethod().equals("GET"))
      {
       //处理 http get请求
       System.out.println("do Get!!");
       
       UserListForm form = new UserListForm();
       form.setPage("1");
       form.setPageSize(getPageSize());
       System.out.println("handleRequestInternal");
       return onSubmit(request, response, form, null);
      }
      else
      {
       //return onSubmit(request, response, null, null);
       System.out.println("do Post!!");
       return super.handleRequestInternal(request, response);
      }
      
     }

     protected ModelAndView onSubmit(HttpServletRequest request,
       HttpServletResponse response, Object command, BindException errors)
       throws Exception {
      //处理http post请求
      UserListForm form = (UserListForm) command;
      System.out.println("user list:" + form);

      List list = this.getDAO().findUsers();
      ArrayList arrList = new ArrayList();
      for (Iterator i = list.iterator(); i.hasNext();) {
       User user = (User) i.next();
       System.out.println(user);
       arrList.add(user);
      }

      PageUtil util = new PageUtil(arrList, form.getPageSize(), form
        .getPage());
      System.out.println("list.size=" + arrList.size());
      request.setAttribute("userlist", util.getArrayList());

      request.setAttribute("pager", util);

      return new ModelAndView(this.getSuccessView());
     }

     public void setDAO(IIbatisDAO dao) {
      currDAO = dao;
     }

     public IIbatisDAO getDAO() {
      return currDAO;
     }
     public String getPageSize()
     {
      return m_pagesize;
     }
     
     public void setPageSize(String pagesize)
     {
      m_pagesize = pagesize;
     }
    }

    具体的velocity内容

     <BODY >
     
        <form name="userlist" method="post" action="/spring/userlist.do">
             <input type="hidden" name="page" >
             <input type="hidden" name="pageSize"  value=2>    
        </form>
     
     <table width="772"  border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="#FFFFFF">
       <tr>
         <td>     
           <table width="750"  border="0" align="center" cellpadding="5" cellspacing="1">
             <tr align="center">
               <td background="images/q_12.gif"><span class="ff">用户名</span></td>
               <td background="images/q_12.gif" class="ff">站点</td>
               <td background="images/q_12.gif"><span class="ff">邮箱</span></td>
             </tr>
     #foreach($user in $userlist)
     #set($color="E9F4FF")
     #if($velocityCount%2==0)
     #set($color="FFFFFF")
     #end
             <tr align="center" bgcolor="$color">
                       <td class="ii">$user.getUsername()</td>         
                             <td>$user.getSite()</td>
                 <td class="style28">$user.getEmail()</td>
             
                     </tr>
     #end       
           </table>
     #set($pageFirst=1)
     
     #if ($pager)
     #set($pageEnd=$pager.getPageCount())
     #set($pagePrevious=$pager.getPreviousPage())
     #set($pageNext = $pager.getNextPage())
     #else
     #set($pageEnd=1)
     #set($pagePrevious=1)
     #set($pageNext =1)
     #end
     <scrīpt>
     
     function goto(p) {
             userlist.page.value=p;
             userlist.pageSize.value=2;
              userlist.submit();
     }
     </scrīpt>
     <table width="100%" border="0">
       <tr>
       <td width="98%" height="43" align="right">
        #if ($pager)
        总 $pager.rowCount 条
        第 $pager.currentPage/$pager.pageCount 页
        #else
        总 0 条
        第 0 页
        #end
        <a href="#$pageFirst" ōnclick="goto($pageFirst)">首页</a>
        <a href="#$pagePrevious" ōnclick="goto($pagePrevious)">上一页</a>
        <a href="#$pageNext" ōnclick="goto($pageNext)">下一页</a>
        <a href="#$pageEnd" ōnclick="goto($pageEnd)">末页</a>
       </td>
       </tr>
     </table>
         </td>
       </tr>
     </table>
     
     </BODY>
     

  • spring + velocity实现分页程序

    2008-9-01

    这段时间用 Spring + ibatis开发一个内部用的管理工具。麻雀随小,但五脏俱全。由于没有用公司的webx框架,重复发明轮子了,也碰到了一些问题。

     

    比如spring+ibatis 分页程序:) .

     

    偶参考网络上的一个实现。实现没有依赖数据库特性。如mysql limit。经过测试成功。

     

    具体的实现PageUtil

     package com.ali.util;

    import java.util.ArrayList;
    import com.ali.db.User;

    public class PageUtil {
     private int currentPage = 0;// 当前页

     private int rowCount = 0;// 总行数

     private int pageSize = 0;// 页大小

     private int pageCount = 0;// 总页数

     private int beginPosition = 0;// 页起始

     private int endPosition = 0;// 页终止

     private boolean hasNextPage = false;// 是否有下一页

     private boolean hasPreviousPage = false;// 是否上一页

     private ArrayList arrayList = new ArrayList();// 记录集

     /**
      * 初始化变量
      *
      * @param rowCount
      * @param pageSize
      * @param currentPage
      */
     public PageUtil(ArrayList arrayList, String pageSize, String currentPage) {
      this.arrayList = arrayList;
      this.rowCount = arrayList.size();

      this.pageSize = Integer.parseInt(pageSize);

      this.getPageCount();
      if (currentPage == null || currentPage.equals("")) {
       this.currentPage = 1;
      } else {
       try {
        this.currentPage = Integer.parseInt(currentPage);
       } catch (NumberFormatException nfe) {
        this.currentPage = 1;
       }
      }
      this.getCurrentPage();
      this.getBeginPosition();
      this.getEndPosition();
     }

     /**
      * 获取总行数
      *
      * @return rowCount
      */
     public int getRowCount() {
      return rowCount;
     }

     public int getPageSize() {
      return pageSize;
     }

     public int getCurrentPage() {
      if (currentPage >= pageCount) {
       currentPage = pageCount;
      } else if (currentPage <= 1) {
       currentPage = 1;
      }
      return currentPage;
     }

     public int getPageCount() {
      // 计算出总页数
      pageCount = (rowCount + pageSize - 1) / pageSize;
      return pageCount;
     }

     public int getBeginPosition() {
      // 计算出页起始
      beginPosition = (currentPage - 1) * pageSize + 1;
      return beginPosition;
     }

     public int getEndPosition() {
      // 计算出页终止
      if (currentPage >= pageCount) {
       endPosition = rowCount;
      } else {
       endPosition = currentPage * pageSize;
      }
      return endPosition;
     }

     public boolean isHasNextPage() {
      // 计算出是否有下一页
      if (currentPage >= pageCount) {
       hasNextPage = false;
      } else {
       hasNextPage = true;
      }
      return hasNextPage;
     }

     public boolean isHasPreviousPage() {
      // 计算出是否有上一页
      if (currentPage <= 1) {
       hasPreviousPage = false;
      } else {
       hasPreviousPage = true;
      }
      return hasPreviousPage;
     }

     public int getFirstPage() {
      return 1;
     }

     public int getPreviousPage() {
      if (this.isHasPreviousPage()) {
       return currentPage - 1;
      }
      return currentPage;
     }

     public int getNextPage() {
      if (this.isHasNextPage()) {
       return currentPage + 1;
      } else {
       return currentPage;
      }
     }

     public int getLastPage() {
      return pageCount;
     }

     /**
      * 获取页数据
      *
      * @return ArrayList
      */
     public ArrayList getArrayList() {

      ArrayList list = new ArrayList();
      for (int i = beginPosition; i <= endPosition; i++) {
       list.add(arrayList.get(i - 1));
      }
      return list;

     }
    }

  • 分布式计算hadoop部署

    2008-8-22

     

    很多人听说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       停止应用

     

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

  • php自动化测试框架---PHP-QAT

    2008-8-20

    一提到web自动化框架/工具,很多同行会想起: watir等。其实PHP的世界一样很精彩,流行PHP测试框架phpunit、simpletest、PHP-QAT 。PHP-QAT 能做单元测试、web应用测试等。

    1 下载安装
    http://downloads.php.net/johannes/php-5.3.0alpha1.tar.gz

    安装php: ./configure;make

    在当前目录有run-tests.php。

    2 环境设置

    export TEST_PHP_EXECUTABLE=/usr/local/bin/php

    3  样例

    $ cd  /usr/local/apache2/php-5.3.0alpha1

    $ ./run-tests.php  xyz/001.phpt  

    =====================================================================
    PHP         : /usr/local/bin/php
    PHP_SAPI    : cli
    PHP_VERSION : 5.3.0alpha1
    ZEND_VERSION: 2.3.0
    PHP_OS      : Linux - Linux alitest146 2.6.9-42.ELsmp #1 SMP Wed Jul 12 23:27:17 EDT 2006 i686
    INI actual  : /usr/local/apache2/php-5.3.0alpha1
    More .INIs  :  
    CWD         : /usr/local/apache2/php-5.3.0alpha1
    Extra dirs  :
    VALGRIND    : Not used
    =====================================================================
    Running selected tests.
    b user is  /usr/local/apache2/php-5.3.0alpha1/xyz/001.phpt  Array/usr/local/apache2/php-5.3.0alpha1/xyz/001.phpt is fileTEST 1/1 [xyPASS Simple POST Method test [xyz/001.phpt]
    =====================================================================
    Number of tests :    1                 1
    Tests skipped   :    0 (  0.0%) --------
    Tests warned    :    0 (  0.0%) (  0.0%)
    Tests failed    :    0 (  0.0%) (  0.0%)
    Expected fail   :    0 (  0.0%) (  0.0%)
    Tests passed    :    1 (100.0%) (100.0%)
    ---------------------------------------------------------------------
    Time taken      :    0 seconds
    =====================================================================

    [root@alitest146 /usr/local/apache2/php-5.3.0alpha1]
    $ cat xyz/001.phpt
    --TEST--
    Simple POST Method test
    --SKIPIF--
    <?php if (php_sapi_name()=='cli') echo 'skip'; ?>
    --POST--
    a=Hello+World
    --FILE--
    <?php
    echo $_POST['a']; ?>
    --EXPECT--
    Hello World

    4更多详细信息参考 http://qa.php.net/write-test.php

    5 改造后的实际应用:

    北京雅虎\阿里妈妈
  • 测试工具loadrunner扩展开发的一点感想

    2008-8-13

    最近在应用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给我,然后彻底解决这个问题该多好啊
  • Jmeter图形化框架

    2008-8-10

    最近在看Jmeter源代码,顺便温习JAVA SwingAPI

     

    为了看得更清楚Jmeter图形化处理,偶尽量剥离Jmeter相关的API ,使用SUN JAVA API

     

    更多请参考经典的JAVA书籍:《Java 2核心技术》。偶的JAVA知识从这2本书开始J

     

    最核心的技术点:

    Ø         JframeJPanel 等容器

    Ø         ActionListener 事件处理

    Ø         ImageIcon 图片展现

    Ø         反射,如commandClass.newInstance

     

     

    package org.apache.jmeter;

    import java.awt.BorderLayout;

    import java.awt.Color;

    import java.awt.Component;

    import java.awt.Container;

    import java.awt.Dimension;

    import java.awt.GridLayout;

    import java.awt.HeadlessException;

    import java.awt.Point;

    import java.awt.event.ActionEvent;

    import java.awt.event.ActionListener;

    import java.awt.event.KeyEvent;

    import java.awt.event.MouseAdapter;

    import java.awt.event.MouseEvent;

    import java.lang.reflect.Modifier;

    import java.util.HashMap;

    import java.util.HashSet;

    import java.util.Iterator;

    import java.util.List;

    import java.util.Map;

    import java.util.Set;

     

    import javax.swing.BorderFactory;

    import javax.swing.Box;

    import javax.swing.BoxLayout;

    import javax.swing.ImageIcon;

    import javax.swing.JButton;

    import javax.swing.JComponent;

    import javax.swing.JDialog;

    import javax.swing.JFrame;

    import javax.swing.JLabel;

    import javax.swing.JMenu;

    import javax.swing.JMenuBar;

    import javax.swing.JMenuItem;

    import javax.swing.JOptionPane;

    import javax.swing.JPanel;

    import javax.swing.JScrollPane;

    import javax.swing.JSplitPane;

    import javax.swing.JMenu;

    import javax.swing.JMenuBar;

    import javax.swing.KeyStroke;

    import javax.swing.SwingUtilities;

    import javax.swing.border.EmptyBorder;