51Testing软件测试论坛

标题: 将QC的COM接口开放成Rest服务 [打印本页]

作者: CharlesCui    时间: 2009-11-18 16:53
标题: 将QC的COM接口开放成Rest服务
<原文发表在:http://charlescui.javaeye.com/blog/518335>;

以Ruby代码为例,

QC平台的SDK以COM组件的形式对外开放,但这种开放方式只限于本机,如果需要进行远程访问QC开放的接口,需要对这套SDK包装一下,做成标准化的远程通讯协议或方式,比如:ice或者rest。

我的设计是将COM用Ruby包装一下,做成一个对外提供Rest方式接口的QCMetaServer服务器。 过程如下:


首先要访问QC的COM组件,建立全局连接,需要的话可以放到公用的池子里。Ruby做成服务发布的时候通常是按多进程方式发布的,所以一般一个进程一个连接就够了,不需要池子。

其次将所需的所有COM接口封装一下,变成Rest接口,这样可以和其它远程服务器进行通讯。

最后,注意在服务器终止之前释放连接,否则QC的COM会报错:

QCMetaServer.rb:112: [BUG] Segmentation faultruby 1.8.6 (2008-08-11) [i386-mswin32]This application has requested the Runtime to terminate it in an unusual way.Please contact the application’s support team for more information.
QCMetaServer.rb:112: [BUG] Segmentation fault ruby 1.8.6 (2008-08-11) [i386-mswin32] This application has requested the Runtime to terminate it in an unusual way. Please contact the application’s support team for more information.

这个错误对于公司内部少数人使用的情况下没有多大影响,但这种设计对生产环境上的应用来说是不允许的。

对QC接口二次开发之前,需要了解下QC SDK,相关资料请各位网上搜索,我这里资料有限,本人也是边看少而又少的资料,边猜测着开发的。

下面这个图大家引用的较多,这是QC COM中的SDK方法的树状结构图,绝大部分对象都是通过工厂方法生成的,这是规律。


(大家能看见图片么?我编辑的时候可以,发表后不行)

代码如下:

Ruby代码
require 'rubygems'  
require 'activerecord'  
require 'win32ole'  
require 'pp'  
  
p "Global initializion."  
$qc = WIN32OLE.new("TDApiOle80.TDConnection")  
p "Loaded COM => TDApiOle80.TDConnection"  
$qc.InitConnectionEx("http://10.2.226.12/qcbin/");  
p "QC connection init."  
$qc.ConnectProjectEx('ALISOFT_CRM','ALISOFT_CRM2006','cuizheng','');  
p "QC project connection init."  
  
require 'sinatra/base'  
require 'coderay'  
  
class QCMeta < Sinatra::Base  
  
  get '/' do  
    h = {}  
    h[rojectName] = $qc.ProjectName  
    h[:ServerURL] = $qc.ServerURL  
    h[:ServerTime] = $qc.ServerTime  
    h[rojectProperties] = $qc.ProjectProperties  
    h[:ServerName] = $qc.ServerName  
    h.to_xml  
  end  
   
  get '/ole' do  
    h = {  
      "TDApiOle80.TDConnection<functional>" => $qc.ole_func_methods.map{|f|f.to_s},  
      "TDApiOle80.TDConnection<property(get)>" => $qc.ole_get_methods.map{|f|f.to_s},  
      "TDApiOle80.TDConnection<property(set)>" => $qc.ole_put_methods.map{|f|f.to_s}  
    }.to_json  
    params[:color].downcase == "true" ? CodeRay.scan(h,:json).div(:line_number => :tables) : h  
  end  
   
  get '/projects' do  
    {rojectsList => $qc.ProjectsList}.to_xml  
  end  
  
=begin  
  <C#>  
  
  int intSub = 286;  
  SubjectNode nodSub = objTree.get_NodeById(intSub) as SubjectNode;  
  TestFactory objTF = nodSub.TestFactory as TestFactory;  
  lstList = objTF.NewList("");  
  foreach (Test objTest in lstList)  
  {  
  MessageBox.Show((string)objTest.Name);  
  }  
=end  
  
  #~ tm = $qc.TreeManager  
  #~ nod = tm.get_NodeById(id)  
  #~ nod.TestFactory.NewList("").each do |test|  
    #~ pp test.Status  
  #~ end  
  
  
=begin  
  <VB>  
  Dim BugFactory, BugList  
  Set BugFactory = QCConnection.BugFactory  
  Set BugList = BugFactory.NewList("") 'Get a list of all the defects.  
=end  
  
  
  
  get "/bugs" do  
    bf = $qc.BugFactory  
    bflist = bf.NewList("")  
  
    max = params[:max] || 100  
    i = 0  
    h = {}  
    bflist.each do |bug|  
      h[bug.ID] = {  
        :Status => bug.Status,  
        :AssignedTo => bug.AssignedTo,  
        etectedBy => bug.DetectedBy,  
        riority => bug.Priority,  
        :Summary => bug.Summary  
      }  
      i >= max ? break : i+=1  
    end  
    {:BUGS => h,:COUNT => bflist.Count}.to_xml  
  end  
   
  def self.run!(options={},&trap_handler)  
    set options  
    handler      = detect_rack_handler  
    handler_name = handler.name.gsub(/.*::/, '')  
    puts "== Sinatra/#{Sinatra::VERSION} has taken the stage " +  
      "on #{port} for #{environment} with backup from #{handler_name}" unless handler_name =~/cgi/i  
    handler.run self, :Host => host, ort => port do |server|  
      trap(:INT) do  
        trap_handler.call  
        ## Use thins' hard #stop! if available, otherwise just #stop  
        server.respond_to?(:stop!) ? server.stop! : server.stop  
        puts "\n== Sinatra has ended his set (crowd applauds)" unless handler_name =~/cgi/i  
      end  
      set :running, true  
    end  
  rescue Errno::EADDRINUSE => e  
    puts "== Someone is already performing on port #{port}!"  
  end  
end  
  
  
QCMeta.run!(:host=>'0.0.0.0', :port => 4567){  
  begin  
    $qc.DisconnectProject  
    p "QCMeta disconnected to QC."  
    $qc.ReleaseConnection  
    p "QCMeta released to QC."  
    p "QCMeta will shutdown."  
    rescue => e  
    p "QCMeta disconnect and release faile."  
    p "But server still going to shutdown."  
    p e.to  
  end  
}  


服务器启动后,访问如下几个url可得到相应的结果:

http://localhost:4567/(QC的一些信息)

引用
<hash>
<ServerURL>http://10.2.226.12/qcbin<;/ServerURL>
<ServerTime>2009/11/16 10:56:57</ServerTime>
<rojectProperties>#<WIN32OLE:0×2cd0404></ProjectProperties>
<ServerName>http://10.2.226.12/qcbin/wcomsrv.dll<;/ServerName>
<rojectName>ALISOFT_CRM2006</ProjectName>
</hash>


http://localhost:4567/ole(下面是COM中所有方法和属性的列表。)

引用
{”TDApiOle80.TDConnection<property(get)>”=>
["Connected",
"rojectConnected",
"ServerName",
"rojectName",
"TestRepository",
"UserName",
"TestFactory",
"BugFactory",
"TestSetFactory",
"UserGroupsList",
"HostFactory",
"VCS",
"rojectsList",
"Command",
"TreeManager",
"ReqFactory",
"ActionPermission",
"DBType",
"DBManager",
"Customization",
"Fields",
"CommonSettings",
"UserSettings",
"HostGroupFactory",
"UsersList",
"assword",
"ExtendedStorage",
"DirectoryPath",
"ChangeFactory",
"MailConditions",
"ServerTime",
"TDSettings",
"rojectProperties",
"DomainName",
"TextParam",
"TDParams",
"UsingProgress",
"CheckoutRepository",
"ViewsRepository",
"VcsDbRepository",
"RunFactory",
"ModuleVisible",
"rojectsListEx",
"DomainsList",
"Analysis",
"VMRepository",
"DBName",
"Rules",
"TestSetTreeManager",
"AlertManager",
"AllowReconnect",
"KeepConnection",
"IgnoreHtmlFormat",
"ReportRole",
"ComponentFactory",
"ComponentFolderFactory",
"ServerURL",
"roductInfo"],
“TDApiOle80.TDConnection<property(set)>”=>
["UsingProgress",
"AllowReconnect",
"KeepConnection",
"IgnoreHtmlFormat",
"ClientType"],
“TDApiOle80.TDConnection<functional>”=>
["QueryInterface",
"AddRef",
"Release",
"GetTypeInfoCount",
"GetTypeInfo",
"GetIDsOfNames",
"Invoke",
"InitConnection",
"ReleaseConnection",
"ConnectProject",
"DisconnectProject",
"GetLicense",
"SendMail",
"ChangePassword",
"urgeRuns",
"GetLicenseStatus",
"InitConnectionEx",
"ConnectProjectEx",
"ConnectToVCSAs",
"GetLicenses",
"SynchronizeFollowUps",
"GetTDVersion",
"GetTypeInfoCount",
"GetTypeInfo",
"GetIDsOfNames",
"Invoke"]}



http://localhost:4567/projects(得到QC中项目列表,COM中的ProjectsList对象怎么使用还没有找到文档)

引用
<hash>
<;ProjectsList>#<WIN32OLE:0×344f07c></ProjectsList>
</hash>



http://localhost:4567/bugs(显示当前项目的Bug信息,目前有乱码问题。通过max参数控制显示的数量)

引用
<hash>
<BUGS>
<85>
<Summary>2¿ÃÅÃèêöÎa511¸ö×Ö·ûμÄ2¿ÃÅ£¬Ôú2¿ÃÅDÅÏ¢μÄ2¿ÃÅÃèêöÖDÎT·¨ÏÔê¾</Summary>
<AssignedTo>quake.hongwq</AssignedTo>
<DetectedBy>snake.zhangw</DetectedBy>
<Status>Closed</Status>
<;Priority></Priority>
</85>
<9>
<Summary>2úÆ·DÅÏ¢ÏÔê¾2»íêÕû</Summary>
<AssignedTo>morgan.zhul</AssignedTo>
<DetectedBy>snake.zhangw</DetectedBy>
<Status>Closed</Status>
<;Priority></Priority>
</9>
<47>
<Summary>±¨¼Û′òó¡Ô¤ààò3ûóD′òó¡oí·μ»Ø°′Å¥</Summary>
<AssignedTo>morgan.zhul</AssignedTo>
<DetectedBy>jack</DetectedBy>
<Status>Closed</Status>
<;Priority></Priority>
</47>
<28>
<Summary>êäèë·Ç·¨ò3Â룬3ö′í</Summary>
<AssignedTo>quake.hongwq</AssignedTo>
<DetectedBy>jack</DetectedBy>
<Status>Closed</Status>
<;Priority></Priority>
</28>
<66>

[ 本帖最后由 CharlesCui 于 2009-11-18 16:55 编辑 ]
作者: dimang11    时间: 2009-11-24 15:32
标题: 大哥你太有才
可是~你搞这么个代理~是如何应用?我用C#的访问QC老出问题




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2