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

发布新日志

  • 单元测试文档的重要性-wxc

    2008-11-22 00:15:53

    随着部门人数的激增,基础研发和基础平台的应运而生。对我们的挑战则是持续集成测试。

    现实情况是需求不可能一成不变,在后期的coding阶段总会由于这样那样的原因而改变,同理设计文档也是。而后期的修改文档的作用是那么的微不足道,那么唯一的突破点貌似只有单元测试文档了。

    假定我们开发和测试资源都充足的情况下,其好处是显而易见的:

    1.先写单元测试用例,再写代码,可以有效的抑制开发的代码变动量

    2.即使变动,QA也可以第一时间通过单元测试文档获得代码变动情况,调整测试脚本,使得daily test成为可能。否则API测试也只能是在外面隔靴搔痒,而不能真正深入代码深处。 

    3.性能测试发生问题往往是,譬如java数据池中记得建立链接,而忘了关闭链接。c中队列资源使用后的忘记回收。而单元测试则可以提前消灭这些问题。那么是不是投入资源到单元测试更有效呢。

    4.最重要的一点,把单元测试文档纳入svn的管理,进行版本控制。一份代码,一份单元测试文档。

    有句挺有意思的话是这么说:两台电视机,其中一台每个电阻元器件都进行了检验,再组装,整体检验;另外一台,则不管三七二十一,组装为一整体,再进行各项功能测试;那么那台电视机的质量会更让人放心呢,我想答案是很明显的。

  • JAVA持续集成解决方案

    2008-11-21 00:22:46

    敏捷方法倡导java持续集成,并输送很多有用的工具。
    当前比较流行的持续集成服务工具有
    1) apache continuum
    2) CruiseControl
     
       配套做持续集成的工具包有
       1) JUnit 单元测试
       2) JUnitPerft或者eclipse tptp 做单元性能测试
       3) 数据库DDL初始化语句
       4) EasyMock 等模拟工具
       5) PMD,checkStyle,FindBug分析工具
       6)httpUnit HTTP接口测试
       7) purify/Jprofile 动态分析
       8) EMMA/Clover度量代码覆盖率
       9) JAVANCSS度量代码复杂度
       10) JDepend 度量耦合度
       10) 构建工具ant,
       11) 部署脚本
       12)分布式分发框架staf/stax
      
       如上工具通过与持续集成工具粘合,将产生强大威力。
      
       当前阿里巴巴平台架构师采用continuum+maven+mylyn+trac,淘宝采用cruisecontrol做接口测试。
      
  • [论坛] jmeter的linux资源监控器改进

    2008-10-31 22:55:31

    by jack


    针对之前所写的linux服务器资源监控http://bbs.51testing.com/viewthread.php?tid=122321做了改进
    ajm是新的linux服务器端监控,不依赖web server,无需http服务器
    使用方法:
    登录到服务器host_xxx上
    将ajm.tar.gz放到服务器上
    解压缩
    tar -xvzf ajm.tar.gz
    进入ajm目录
    cd ajm
    运行ajm
    ./ajmctl start
    停止ajm
    ./ajmctl stop
    在客户端监控时,可以用
    http://host_xxx:6688/status来获取监控结果的xml
    注意:监控端口为6688,须确保该端口不被占用

    附件中是打好的工具包,欢迎大家下载试用,请不要吝惜您的意见建议!

    [ 本帖最后由 qaarchitech 于 2008-10-31 22:54 编辑 ]

    ajm.tar.gz
    (2008-10-31 22:52:25, Size: 4.98 kB, Downloads: 0)

  • java web tomcat eclipse环境搭建

    2008-10-30 19:28:31

    一.基本工具安装

    JDK安装

    下载安装文件点击安装就可

    环境变量的设置

    JAVA_HOME C:\Program Files\Java\jdk1.5.0_07\

    Path 中加 C:\Program Files\Java\jdk1.5.0_07\bin;

    Eclipse安装

           下载,解压目录就可以

    Tomcat 安装

    二.几种搭建方法

    方法

    Jsp页面

    特点

    方便性

    antx + tomcatPluginV321.zip

    不支持

    需要同步
    antx
    自动创建web框架

    一般

    myeclipse

    支持

    创建j2ee框架

    方便

    lomboz

    支持

    能创建动态的web
    没有框架

    一般

    运用 tomcatPluginV321.zip

    不支持

    纯框架配置

    不方便

     

    1)      运用 myeclipse 插件安装

    Myeclipse安装
    选择你的eclipse所在目录,其它都点下一步,默认安装。 
    .
    安装完毕之后,找到myeclipse的安装目录

     
    featuresplugins2个目录复制在eclipse目录中就可以

    由于myeclipse是不是免费软件,需要注册,如果公司用就要用正版的了!

    注册过程

    点击 Window ----> Preferences ----> Subscrīption ----> Enter Subscrīption, 输入注册码

     

    设定Eclipse+MyEclipseJRE
    一般情况下,Eclipse可以自动找到JRE,我们不用进行过多的设置

    主要注意

    Window ----> Preferences -> myeclipse ->Tomcat5 配置相应的目录就可以

     

    2)      运用 lomboz 插件安装

    Lomboz 安装,

    lomboz-S-3.2RC2-200608081203.zip
    lomboz-wtp-emf-gef-jem-3.1.2.zip 
    lomboz-and-prereqs-S-3.2RC2-200608081203.zip

    解压文件,把目录文件拷贝到eclipse目录中就可

    配置tomcat ,新建server服务就可以运行了

    3)      直接运用 tomcatPluginV321.zip

    解压文件,把目录文件拷贝到eclipse目录中就可

    配置tomcat
    Window ----> Preferences -> Tomcat5
    配置相应的目录就可以

    注意 context declaration mode 选择server.xml 就可以了

     

    4)      运用antx + tomcatPluginV321.zip

    Antx是公司技术运行环境,使用也很简单

    首先我们得到antx,在公司的svn下载
    http://opentech.alibaba-inc.com/community/entry.jspa?externalID=649&categoryID=73
    有详细的说明

    注要注意几点:

    添加PATH路径:将antx\dist\antx\bin目录添加到PATH环境变量中。

    Checkout Antx 第二方类库。
    新建
    antx.properties文件,在新建项目文档中创建文件就可以

    antx.repository.external  = mydir/repository          # 第三方类库
    antx.repository.project   = mydir/repository.project    #
    第二方类库

    petstore.work    = D:/Tomcat/webapps/workshop     //

    安装Antxclipse插件

    根据同步配置 D:/Tomcat/webapps/workshop

    然后我们利用 tomcatPluginV321.zip就可以看到tomcat调试日志了

  • watir 对象tag与attribute扩展简例

    2008-10-28 20:15:10

     

    By Wiston Li

    一,属性扩展在element.rb中

    一段代码,需要实现某个表中单元格判断是否有文本和图片,再进行点击操作

    t = ie.table(:index,  7)     
      for i in 1..t.row_count 
          t[i].each do |cell| 
              if cell.text == _userid.to_s
                      if cell.image(:src, /enabled/).exists?
                        $atag = cell.link(:index,1)
                      end
             end
          end
         end

    若在element中扩展如下代码:

       class Watir::Element
         def has_enabled_image_and_text_is name
           text == name && self.image(:src, /enabled/).exists?
           end
         end

    就可以方便在属性直接来进行对象识别,如下:

     $atag = t.cell(:has_enabled_image_and_text_is =>
      _userid.to_s).link(:index, 1)

     

     

    二,tag扩展在NonControlElement中

    看了一下NonControlElement中的代码,扩展了很多pre, map, li之类的tag对象识别,如在我们的程序中有一叫做object的tag, 我想可以类推如下:

    先添加tag

    module Watir
      class Object < NonControlElement
        TAG = 'OBJECT'
      end
    end

    然后再用脚本

    ie.frame(:id, 'url').object(:id, 'xobject')

     

  • 快速生成页面对象,高效开发watir脚本

    2008-10-28 19:57:18

    By Wiston Li

    在watir对象识别时,需要借助第三方工具来进行页面对象识别,下面的方法类似QTP描述性编程

    生成某类型的对象集合,因而从控制台上可以批量获得对象属性。

    实际上在watir中已经给出部分show_object的方法,下面代码主要给出watir暂且不提供对

    input tag的对象解析的解决方案。

    =begin rdoc
          功能目的:计算某对象的xpath
          输入参数及描述:object
          返回参数及描述:
          调用方法:               
    =end
        def calculate_xpath(object)
          s = ""
          curr = object
          s = "/#{curr.invoke("tagName")}[#{get_index(curr)}]" + s
          par = curr.invoke("parentElement")
          while par.invoke("tagName").downcase != "body"
            s = "/#{par.invoke("tagName")}[#{get_index(par)}]" + s
            par = par.invoke("parentElement")
          end
          return s.gsub(/\[1\]/, "").downcase
        end

    =begin rdoc
          功能目的:计算某对象的xpath tag中索引
          输入参数及描述:object
          返回参数及描述:
          调用方法:               
    =end

        def get_index(currObj)
          par = currObj.invoke("parentElement")
          valuecurr =  currObj.invoke("uniqueID")
          valuepar = par.invoke("uniqueID")
          currtagname = currObj.invoke('tagName').downcase
          count = 0
          par.invoke("children").each { |i|
            val = i.invoke('tagName').downcase
            if val.eql?(currtagname)
              count += 1
              return count if valuecurr.eql?("#{i.invoke("uniqueID")}")
            end
          }
        end

       
    =begin rdoc
       
          功能目的:生成当前document中对象集合
          输入参数及描述:objecttype生成指定的对象类型, props=nil 属性名称
          返回参数及描述:
          调用方法:
                   
    =end
       
        def show_inputs( objecttype, props=nil )
        
          props = ["type","id","name","value","tabIndex","readonly"] unless props
      
      
          divs = document.getElementsByTagName("INPUT")
          puts "Found #{divs.length} Input tags"
          s = ""
          index = 0
          divs.each do |d|
            val = d.invoke('type').downcase
            case  objecttype
            when "edit"
              result=val.eql?("text") || val.eql?("password")
            when "button"
              result=val.eql?("submit")|| val.eql?("button")
            when "checkbox"
              result=val.eql?("checkbox")
            when "radio"
              result=val.eql?("radio")
            end
          
            if result
              index += 1
              s = "#{index} "
              props.each_with_index { |prop,i|
                begin
                  s += prop +":" + d.invoke(prop) + " | "
                rescue
                  #puts "got error - #{prop}"
                end
              }
              s = s + "Xpath: " + calculate_xpath(d)
              puts s
            end
          end
        end

      end
    end

  • [watir] 弹出框的另一种解决方法

    2008-10-28 14:22:37

      watir对于弹出框的处理一直都不是非常的好,网上很多的解决方案都是采用autoit的方法来解决的。其实,使用win32api中自带的方法,也能解决这个问题,而且,可能效率更高。

     我们主要用到以下几个win32api的函数:

     FindWindowEx #可以根据handle值获取特定类的子类的句柄

     SendMessage #发送win32消息

     GetWindowText #取得空间的caption或者title属性

    其中的几个常量

    WM_CLICK = 0x00F5

    IDC_BUTTON1 = 1000

    我们先声明这些win32函数

    require 'win32API'

     SendMessage = Win32API.new('user32.dll','SendMessageA',['l','l','l','l'],'v')

    FindWindowEx = Win32API.new('user32.dll','FindWindowExA',['l','l','p','p'],'l')

    GetWindowText = Win32API.new('user32.dll','GetWindowTextA',['l','p','l'],'l')

    我们先找到ie的弹出框。

    hwnd =ie.hwnd #根据ie对象获取他的hwnd值

    popup_hwnd = FindWindowEx.call(hwnd,0,"#32770",nil) #'#32770'是ie弹出框的类名

    #找到弹出框后,遍历弹出框上的button控件

    button_hwnds =Array.new

    button_hwnd = FindWindowEx.call(popup_hwnd,0,"button",nil)

    while button_hwnd!=0

     button_hwnds << button_hwnd

     button_hwnd = FindWindowEx.call(popup_hwnd,0,"button",nil)

    end

    #找到button的集合后,要点第i个button,直接使用button_hwnd[i]

    #调用sendmessage点击按钮

    SendMessage.call(button_hwnd[i], WM_CLICK,IDC_BUTTON1,0)

    SendMessage.call(button_hwnd[i], WM_CLICK,IDC_BUTTON1,0) #在实际的使用过程中,发现需要调用2次wm_click消息,不知道为什么

     

    使用这个方法,还可以根据button上的文字来点击

    主要是使用GetWindowText方法,这里不做详细的讲解

     

  • [ruby] 创建自己的gem包

    2008-10-28 09:45:52

                                           -----by nish

    RubyGems是一个库和程序的标准化打包以及安装框架,它使定位、安装、升级和卸载Ruby包变的很容易。rails以及它的大部分插件都是以gem形式发布的。本文描述一个自己创建ruby Gems的过程。 gem可以使用你现有的文件夹结构,也可以使用命令创建一个标准的gem包结构。下面是用命令创建一个标准的gem包。

    运行: gpgen yourgem  

    运行完后,会自动生成一个标准的gem包结构:

    yourgem

      COPYING

      LICENSE

      Rakefile

      README

    ├─lib

      └─yourgem

              init.rb

    └─resources

            defaults.yaml

     

    将自己的代码放在lib/yourgem文件夹下,如果有测试代码,则创建一个test目录,将单元测试的文件都放在这个文件夹下。

    将你自己写的rb文件都放在lib/yourgem文件夹下面,比如有a.rb,b.rb

    一般的做法,会在lib的根目录下建立一个 yourgem.rb文件,这个文件用来引入你lib/yourgem文件夹下的所有rb文件。yourgem.rb文件的内容为:

    #yourgem.rb

     $:.unshift"#{File.dirname(__FILE__)}/yourgem"

    require ‘a’

    require ‘b’

     

    制作完rb文件后,修改Rakefile

    # Rakefile

    require 'rake'

    require 'rake/testtask'

    require 'rake/clean'

    require 'rake/gempackagetask'

    require 'rake/rdoctask'

    require 'fileutils'

    include FileUtils

     

    version="0.1.1"  #改为你的version

    name="yourgem"    #改为你的gem名字

     

    spec = Gem::Specification.new do |s|

      s.name = name

      s.version = version

      s.email="your-email@email.com" 

      s.homepage = "http://localhost"

      s.descrīption = s.summary = "xxxxxxxxxxxxx”

      s.author = "xxxx"

      s.add_dependency('gem_plugin', '>= 0.2.3')

     

      s.platform = Gem::Platform::RUBY

      s.has_rdoc = true

      s.extra_rdoc_files = ["README"]

     

     

     

      candidates = %w(COPYING LICENSE README Rakefile) +

        Dir.glob("{bin,doc/rdoc,test,lib}/**/*") +

        Dir.glob("ext/**/*.{h,c,rb}") +

        Dir.glob("examples/**/*.rb") +

        Dir.glob("tools/*.rb") +

        Dir.glob("resources/**/*")

     

      s.files = candidates.delete_if do |item|   #去掉svvrdoc目录

                            item.include?(".svn") || item.include?("rdoc")

                        end

     

      s.require_path = "lib"

      s.bindir = "bin"

    end

     

    Rake::GemPackageTask.new(spec) do |p|

      p.need_tar = true if RUBY_PLATFORM !~ /mswin/

    end

     

    task :install => [:test, :package] do

      sh %{sudo gem install pkg/#{name}-#{version}.gem}

    end

     

    task :uninstall => [:clean] do

      sh %{sudo gem uninstall #{name}}

    end

     

    Rake::TestTask.new do |t|

      t.libs << "test"

      t.test_files = FileList['test/test*.rb']

      t.verbose = true

    end

     

    Rake::RDocTask.new do |rdoc|

      rdoc.rdoc_dir = 'doc/rdoc'

      rdoc.options << '--line-numbers'

      rdoc.rdoc_files.add ['README', 'LICENSE', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc']

    end

     

    task :default => [:test, :package]

     

    CLEAN.include ['build/*', '**/*.o', '**/*.so', '**/*.a', 'lib/*-*', '**/*.log', 'pkg', 'lib/*.bundle', '*.gem', '.config']

     

     

    在当前目录运行

    Gem build Rakefile

     

    运行完成后就会自动生成一个gem,然后你就可以按照gem的语法安装,卸载,升级(可以自己制定gem的地址,或者把它上传到gem pluginserver)这个gem包了

     

  • 改写jQuery实现固定表头,滚动内容

    2008-10-26 01:00:18

     

     

    参考 http://blog.csdn.net/hu_zhenghui/archive/2007/12/02/1911733.aspx

     

     

    原来事件处理采用:

     

    <scrīpt src="scrīpts/jQuery.js"></scrīpt>

      <scrīpt>

          $(document).ready(function () {

           

              $("#tableContainer").scroll(function () {

                 // $("#divx").get(0).scrollLeft = this.scrollLeft;

                  $("#divy").get(0).scrollTop = this.scrollTop;

              });

             

             

          });

      </scrīpt>

     

    例子采用3个表,存在列宽/行高同步的问题。

     

    偶改写了事件,特别注意标红色的style 要素overflow

     

     

           <div id="tableContainer" style="width:1000px; height:600px; overflow:scroll">

    <table border="1" cellpadding="0" cellspacing="0" width="100%" class="scrollTable"  id="scrollTable" >

    <thead>

           <tr>

           <th>

                         <div> 标题</div>

    </th>

    <tr>

    </thead>

    <tbody id="tbSCMProject" class="tbSCMProject">

    </tbody> 

     

     

    <td valign="top"  >

                                       <div id="divy" style="width:300px; height:600px; overflow:hidden">  

    <table id="table_y" border="3">

                                                       

                        <tr><div style="height:51.5px">内容       </div>

                                </tr>

                                                                                                                                         </table>          

     

    </div>

     

     

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

     

     var divScrollHander= function()

    {

                                       var thisContainer = document.getElementById('tableContainer');

                                       var ōbjdivy =    document.getElementById('divy');

                                       if (!thisContainer || !objdivy)

                                       {

                                                           

                                                      return;

                                       }    

                                      

                                       objdivy.scrollTop=thisContainer.scrollTop;

        }

       

       

      tableContainer.attachEvent('onscroll',divScrollHander);

       

    </scrīpt>

     

    </body>

     

     

    由于采用2个表,如何让2个表的行高度一致,不至于适配?下面的图看到,需要2个表的同一行移动需要同步。

     

     

     

  • 虚拟化技术

    2008-10-24 14:37:59

      当前,虚拟化技术已经成为服务器市场当之无愧的热点。一方面是可以直接减少服务器的购买数量。另外一方面是可以提高生产效率。目前来看,powderedge系列至少需要4核cpu,8G内存,上百G的大容量硬盘。

      linux阵营XEN是虚拟化技术中比较流行的一种解决方案。

      基于Xen的操作系统,有多个层,最底层和最高特权层是 Xen程序本身。Xen 可以管理多个客户操作系统,每个操作系统都能在一个安全的虚拟机中实现。在Xen的术语中,Domain由Xen控制,以高效的利用CPU的物理资源。每个客户操作系统可以管理它自身的应用。这种管理包括每个程序在规定时间内的响应到执行,是通过Xen调度到虚拟机中实现。
      当Xen启动运行后,第一个虚拟的操作系统,就是Xen本身,我们通过xm list,会发现有一个Domain 0的虚拟机。Domain 0 是其它虚拟主机的管理者和控制者,Domain 0 可以构建其它的更多的Domain ,并管理虚拟设备。它还能执行管理任务,比如虚拟机的体眠、唤醒和迁移其它虚拟机。
    一个被称为xend的服务器进程通过domain 0来管理系统,Xend 负责管理众多的虚拟主机,并且提供进入这些系统的控制台。命令经一个命令行的工具通过一个HTTP的接口被传送到xend

  • [rails学习] 在rails中使用thickbox.js

    2008-10-22 17:36:46

                                                                     ----by Nish

      thickbox.js是一个基于jquery的很不错的插件,但是由于rails默认的使用的是Prototype这个Ajax库,所以在rails中简单的通过以下代码,会出现jquery与Prototype的冲突。

      <%= javascrīpt_include_tag  'jquery' %> 
      <%= javascrīpt_include_tag 'thickbox'%>
      <%= stylesheet_link_tag "thickbox" %>

     目前有2种方法可以解决上面的方法:

    第一种是在引入上述js库中,增加一行代码 <scrīpt> jQuery.noConflict(); </scrīpt> ,即上述代码改为:

      <%= javascrīpt_include_tag  'jquery' %> 
      <%= javascrīpt_include_tag 'thickbox'%>
      <%= stylesheet_link_tag "thickbox" %>

      <scrīpt> jQuery.noConflict(); </scrīpt>


    第二种方式是使用jrails代替默认的 Prototype库。

    jrais可以通过下面命令进行安装

    ruby ./scrīpt/plugin install http://ennerchi.googlecode.com/svn/trunk/plugins/jrails

    安装完成后,会自动把jrails用的js文件拷贝到Javascrīpt文件夹下,然后删除所有Prototype库所带的的js文件,通过下面的代码就可以正常的使用thickbox,并且,默认的,rails用的ajax库改成了jquery

      <%= javascrīpt_include_tag  :default%> 
      <%= javascrīpt_include_tag 'thickbox'%>
      <%= stylesheet_link_tag "thickbox" %>

    或者

      <%= javascrīpt_include_tag  'jquery','jquery-ui','jrails'%> 
      <%= javascrīpt_include_tag 'thickbox'%>
      <%= stylesheet_link_tag "thickbox" %>

  • 子html 页面刷新父页面并关闭

    2008-10-16 01:11:58

    Child.html 关闭刷新父页面并关闭

     

     

    if (window.opener && !window.opener.closed) {

                                      

                                              var site=document.getElementById("hidden_currSite").value;

                                             

                                              var publishdate=document.getElementById("publishdate").value;

                                             

                                              var str_url="project.do?site="+site +"&publishdate="+publishdate;

                                                                                        window.opener.location.href=str_url;          

                                              //window.opener.location.reload();                         

             }

     

    window.close();

     

     

    html页面:

     

    window.open("child.htm ?projectid="+projectid+"&site="+site);

     

    同时为了保证取到更新的数据,应该禁止cache

    <Html>

    <head>

           <meta http-equiv="pragma" content="no-cache">

     <meta http-equiv="cache-control" content="no-cache, must-revalidate"> 

        <meta http-equiv="expires" content="0">

    </head>

     

     

    有朋友可能对不用window.opener.location.reload(); 存疑。

     

    当父页面之前是http post 请求,用window.opener.location.reload(); 会导致再次Post,这个可能不是我们期望的结果。

     

  • ruby设置windows环境变量

    2008-10-08 11:25:23

    by jiale

    ruby可以使用win32ole.new("Wscrīpt.Shell")的Environment操作windows环境变量

    获取环境变量:

    win32ole.new("Wscrīpt.Shell").Environment(type).Item(name)

    type:system(系统)、user(用户)

    name:环境变量名

    设置环境变量:

    vbs的做法:

    可以直接使用

    win32ole.new("Wscrīpt.Shell").Environment(type).item(name) = value

    但在ruby中item(name) = value会抛语法异常

    ruby的做法:

    win32ole.new("Wscrīpt.Shell").Environment(type)["item",name] = value

    或者使用setproperty方法

    win32ole.new("Wscrīpt.Shell").Environment(type).setproperty("item", name, value)

  • ruby获取目标页面源文件

    2008-10-08 09:58:03

    by jiale

    #获取http源文件

    require 'net/http'
    def get_httpsource(searchurl)
       begin
          url = URI.parse(searchurl)
          res = Net::HTTP.get(url)
          return res
       rescue => err
          puts err
          raise err
       end
    end

  • Ruby获取当前的执行文件的路径和目录

    2008-10-08 09:53:21

    by jiale

    获得当前执行文件的文件名:

    __FILE__

    获得当前文件的目录

    File.dirname(__FILE__)

    获得当前执行文件的完整路径(绝对路径)

    require ‘pathname’
    Pathname.new(__FILE__).realpath

    获得当前执行文件的目录完整路径(绝对路径)

    require ‘pathname’
    Pathname.new(File.dirname(__FILE__)).realpath

  • su -和login shell

    2008-10-07 16:48:41

    最近部署一个java程序的时候,root用户执行jboss的启动脚本,反复提示jdk程序出错。

    但是该脚本据上次正确执行后未被改动,且曾经被正确执行无数遍了。那问题出在哪里呢?

    后来反复实践,发现我是在admin用户下su到root用户,没有正确加载环境变量所致。

    只要在su后面加一个“-”,问题迎刃而解,原来小小的“-”是罪魁祸首。

    下面再强调下基本概念,血的教训啊

    login shell会执行/etc/profile和.bash_profile,/etc/bashrc和.bashrc
    non-login shell则仅执行/etc/bashrc和.bashrc
    查看su的man手册,su - 切换用户将会使用login shell;不带-的话,则会使用non-login shell
    PS:在RHEL下,辨别login和non-login shell另外一种方法是:exit命令后如果会清屏则是login shell,反之则是non-login shell
  • Spring Velocity macro应用与调试

    2008-09-26 22:14:24

     

      默认情况下,velocity macro文件修改没有被应用服务器检测,必须重启才能生效。

     

     

    Spring  web.xml contextConfigLocation配置包含属性文件mvc-config.xml

     

    <servlet>

    <servlet-name>dispatcherServlet</servlet-name>     

    <servlet-class>  org.springframework.web.servlet.DispatcherServlet        </servlet-class>      

    <init-param>          

    <param-name>contextConfigLocation</param-name>         

    <param-value>

    /WEB-INF/mvc-config.xml

    /WEB-INF/alert-config.xml

    </param-value>   

    </init-param>  

    <load-on-startup>1</load-on-startup>  

     </servlet>

     

     

    mvc-config.xml 部分内容如下:

     

                  <bean id="velocityConfigurer"                           class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">

                  <property name="resourceLoaderPath">

                  <value>WEB-INF/velocity/</value>  

                  </property>

                  <property name="velocityProperties">

                         <props>

                         <prop key="input.encoding">gb2312</prop>

                         <prop key="output.encoding">gb2312</prop>

                         <prop key="contentType">text/html;charset=gb2312</prop>

                         <prop key="file.resource.loader.cache">false</prop>

                         <prop key="file.resource.loader.modificationCheckInterval">1</prop>

                         <prop key="velocimacro.library.autoreload">true</prop>

                         <prop key="velocimacro.library">templates.vm</prop>

                         <prop key="runtime.log.logsystem.class">org.apache.velocity.runtime.log.SimpleLog4JLogSystem</prop>

                         <prop key="runtime.log">com.ali</prop>

                         <prop key="runtime.log.error.stacktrace">true</prop>

                         <prop key="runtime.log.warn.stacktrace">true</prop>

                         <prop key="runtime.log.info.stacktrace">false</prop>

                         <prop key="runtime.log.invalid.reference">true</prop>

                  </props>

                  </property>

     

           </bean>

          

             <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">

               <property name="suffix"><value>.vm</value></property>

                         <property name="exposeSpringMacroHelpers"><value>true</value></property>

                         <property name="exposeRequestAttributes"><value>true</value></property>

                         <property name="exposeSessionAttributes"><value>true</value></property>

                         <property name="contentType" value="text/html;charset=gb2312" />

                         <property name="dateToolAttribute">

          <value>dateTool</value>

               </property>

            </bean>

     

     

     

    Velocity 文件包括库文件templates.vm都放在WEB-INF/velocity/

    确保velocity文件被修改都立即重新扫描,关键的参数:

    <prop key="file.resource.loader.cache">false</prop>

                         <prop key="file.resource.loader.modificationCheckInterval">1</prop>

                         <prop key="velocimacro.library.autoreload">true</prop>

     

     

    index.vm上通过:

    #parse("templates.vm") 引入velocity 模版。

     

  • 一次mysql部分汉字乱码解决过程

    2008-09-26 22:09:53

     

        从Confluence db导出数据在mysql控制台上乱码,在SPRING MVC页面也乱码,如。从confunce应用页面上看,无乱码。到底原因在哪里呢?

     

    由于涉及的层非常多,只能用隔离法。

        主要有几种可能

    1)      db里面的数据是否真有乱码

    2)      输出到页面上的汉字有乱码

    3)      页面编码识别有错

     

    1.1.1    mysql 控制台检查:

    mysql> show variables  like  'char%';

    +--------------------------+-----------------------------------+

    | Variable_name            | Value                             |

    +--------------------------+-----------------------------------+

    | character_set_client     | gb2312                            |

    | character_set_connection | gb2312                            |

    | character_set_database   | utf8                              |

    | character_set_filesystem | binary                            |

    | character_set_results    | gb2312                            |

    | character_set_server     | utf8                              |

    | character_set_system     | utf8                              |

    | character_sets_dir       | D:\MySQLServer5.0\share\charsets\ |

    +--------------------------+-----------------------------------+

    8 rows in set (0.05 sec)

     

    mysql> show variables  like  'coll%';

    +----------------------+-------------------+

    | Variable_name        | Value             |

    +----------------------+-------------------+

    | collation_connection | gb2312_chinese_ci |

    | collation_database   | utf8_general_ci   |

    | collation_server     | utf8_general_ci   |

    +----------------------+-------------------+

    3 rows in set (0.00 sec)

     

     

    在控制台依然乱码。

     

    下载MYSQL Administrator,用Mysql query browser查看,OK的。

     

    只能剩下2种可能了。

     

    1.1.2    JDBC直接连接DB

    String url =     "jdbc:mysql://127.0.0.1:3306/scmproj?user=root&password=mysql&useUnicode=true&characterEncoding=GB2312";

     

                         java.sql.Connection con = DriverManager.getConnection(url);

     

                         Statement stmt = con.createStatement();

     

          

                         String query = "select * from users where email='yi.suy@alibaba-inc.com'";

     

                         ResultSet rs = stmt.executeQuery(query);

     

                while (rs.next())

     

                         {

                                // System.out.println(new

                                // String(rs.getString(1).getBytes("UTF8")).toString());

                                System.out.println(new String(rs.getString("fullname")));

                         }

      

      同样输出正确。

     

    1.1.3    IBATIS API连接DB

    private static SqlMapClient sqlMapper;

     

    private static SqlMapClient sqlMapper;  Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");

                         // Reader reader =

                         // Resources.getResourceAsReader("D:/eclipse-SDK-3.3.2-win32/project/SCMProj/bin/SqlMapConfig.xml");

                         sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader);

                         reader.close();

     

    List list =sqlMapper.queryForList("getProjectByName", queryStr);

                                        SCMProject proj=(SCMProject) list.get(0);

     

    正常。

     

    剩下来的就是检查SPRING的编码格式了。

     

    最后锁定SPRING   VelocityViewResolver

    <property name="contentType" value="text/html;charset=UTF-8" />

     

  • 批量点击链接(去重)

    2008-09-24 19:26:45

    by jack

    日前忽然有人问我,想把一个页面上的搜索结果链接都点一遍分别检查,这个脚本怎么写

    想想这个需求很简单,就顺手用descrīption对象写了,以口碑网搜索结果为例,脚本如下:

    SystemUtil.Run "http://bendi.koubei.com/search/searchlocal.html?option.key=%D1%C5%CA%CB%D4%B7&option.cityname=%BA%BC%D6%DD&searchFlag=1&city=2595"


    Set ōDesc = Descrīption.Create()

    oDesc("micclass").Value="Link"
    oDesc("url").Value="http://hangzhou.koubei.com/store/detail--storeId-.*"

    Set Lists = Browser("title:=雅虎口碑.*").Page("title:=雅虎口碑.*").ChildObjects(oDesc)
    NumberOfLists = Lists.Count()

    For i = 0 To NumberOfLists - 1 
      Lists(i).click
      ……
    Next

    点击的都是http://hangzhou.koubei.com/store/detail--storeId-这种格式的链接,也就是结果链接的统一格式

    这里有个点要注意:descrīption对象默认就是支持正则表达式的,可以用正则表达式作为属性值

    但是很快就反馈回来一个问题:页面上有重复的链接,这样实际是存在重复点击的;在结果比对时出现了点问题

    想了想,就再加入了一段去重的处理,修改脚本如下:

     

    SystemUtil.Run "http://bendi.koubei.com/search/searchlocal.html?option.key=%D1%C5%CA%CB%D4%B7&option.cityname=%BA%BC%D6%DD&searchFlag=1&city=2595"


    Dim arrClickedLink()
    ReDim Preserve arrClickedLink(0)

    Set ōDesc = Descrīption.Create()

    oDesc("micclass").Value="Link"
    oDesc("url").Value="http://hangzhou.koubei.com/store/detail--storeId-.*"

    Set Lists = Browser("title:=雅虎口碑.*").Page("title:=雅虎口碑.*").ChildObjects(oDesc)
    NumberOfLists = Lists.Count()

    For i = 0 To NumberOfLists - 1
        sCurrentLink = Lists(i).getroproperty("url")
     If not isClickedLink(sCurrentLink) Then
      Lists(i).click
      ……
     End If
    Next

    Function isClickedLink(url)

     iClickedLinkLen = ubound(arrClickedLink)

     For n=0 to iClickedLinkLen
      If url = arrClickedLink(n) Then
       isClickedLink = True
       Exit Function
      End If
     Next

     ReDim Preserve arrClickedLink(iClickedLinkLen+1)
     arrClickedLink(iClickedLinkLen+1) = url
     isClickedLink = False

    End Function

     

     

  • [Ruby学习] 在ruby中调用dll

    2008-09-24 17:19:10

                                                                          -----by Nish 

      开源测试工具watir是采用的ruby语言进行开发的。在研究watir框架的时候,发现有一部分函数watir没有提供而且暂时没找到合适的gem包,而很多功能在我们原来的自动化测试框架中都通过c写的dll进行了实现,于是我们希望能够把这部分的dll无缝的移植到watir上,减少我们的工作量,而且可以更高效的实现我们需要的功能。

      在ruby的开源项目中,Win32Api这个gem可以实现我们需要的功能。通过以下方法 ,我们就可以调用外部dll中的函数。

    Win32Api.new(dllname, proc, import, export)

    参数说明

    dllname:dll文件的名字,如果想只写dll的名字,可以将dll放到system32目录或者当前目录下,或者写上dll文件所在的路径

    proc: dll中函数的名字

    import:函数传入参数的参数类型,其中 "p" 对应指针,"n","l"对应long,"i"对应 int,"v" 对应void,如果有多个参数,可以通过 ["p","n"]数组的方式来实现,其中置为nil可以表示没有参数

    export:函数的返回值类型,参数类型同上

     

    Win32API#call([args ...])

    调用dll中的函数,参数和返回值应该与new申明中的一致,如果返回一个指针,需要事前初始化,否则可能会有内存溢出问题。

     

    例子:

    有个dll的头文件的申明为:

    extern "C" long PASCAL EXPORT BMPToJPG(char *jpg,char *bmp);

    那么在将指定的dll文件放在当前目录,ruby代码如下

    require 'rubygems'

    require 'Win32Api'

    JPG=Win32API.new(File.dirname(__FILE__)+"\\JpgDll.dll","BmpToJpg",["p","p"],"l")

    JPG.call("D:\\1.bmp","D:\\1.jpg")

    执行上述代码后,就能把D盘下的1.bmp文件另存为 1.jpg文件

1562/8<12345678>
Open Toolbar