Skip to content

Instantly share code, notes, and snippets.

@NigelThorne
Last active April 17, 2018 12:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NigelThorne/6102634 to your computer and use it in GitHub Desktop.
Save NigelThorne/6102634 to your computer and use it in GitHub Desktop.
Runs on Windows. Assumes you have QC installed. The code needs some love, but does work.
$:.unshift File.expand_path(File.dirname(__FILE__))
require 'win32ole'
require 'qc_automation'
require 'qc_test'
require 'fileutils'
module QCIntegration
class TestFolder
attr_accessor :kids
end
end
def file_name(test, base_path)
File.join(base_path, test.folder.path.gsub(/^\/Subject\//,""), "#{test.name}.ts")
end
def dump_test_to_file(test, base_path, folder_id)
# file_path = file_name(test, base_path)
folder_path = File.join(base_path, folder_id)
FileUtils.mkdir_p(folder_path)
File.open(File.join(folder_path, "#{test.name}.ts"), 'w+') do |f|
f << test.get_steps_content.join("\n")
end
end
def link_folder(folder, base_path)
return if folder.id == -1
FileUtils.mkdir_p(File.join(base_path, folder.id.to_s))
name = folder.desc
name = "root" if name.length == 0
#FileUtils.ln_s("#{base_path}\\#{folder.father_id}\\#{name}", "#{base_path}\\#{folder.id}")
puts `#{base_path}link.bat "#{base_path}#{folder.father_id}\\#{folder.desc}" "#{base_path}#{folder.id}"`
end
def link_folders(father, base_path)
return unless father.kids
father.kids.each{|kid|
link_folder(kid, base_path)
link_folders(kid, base_path)
}
end
exit if Object.const_defined?(:Ocra)
Settings = Struct.new(:url, :username,:password,:project)
settings = Settings.new("http://your.qc.address:8080/qcbin","user","password","project") #assumes DEFAULT
@qc = QCIntegration::QCAutomation.new(settings, $stdout)
@qc.open
@qc.folders.values.compact.each{|f|
if(f.father)
f.father.kids ||= []
f.father.kids << f
end
}
BASE_PATH = 'C:\\QC_BOND_Q_Tests\\'
link_folders(@qc.root_folder, BASE_PATH)
@qc.find_all_tests.each{ |id, name, father_id|
test = @qc.find_test_by_id(id)
begin
dump_test_to_file(test, BASE_PATH, father_id)
rescue => e
puts e.message
end
}
puts "done"
@qc.close
module QCIntegration
class TestFolder
attr_reader :id, :father_id,:desc
def initialize(id, father_id, desc, nodes)
#puts "New Folder: #{id}\t#{desc}"
@id, @father_id, @desc, @nodes = id, father_id, desc, nodes
end
def path
"#{father ? father.path : ""}#{desc}/"
end
def father
f = @nodes[father_id]
end
end
# begin
# qc = QCIntegration::QCAutomation.new(QcSetting.first, $stdout)
# qc.open
# t = qc.find_test_by_name('"Bond Advance TS Test Cases/Functional/Functional - Manage Protocols FR"', "Create Preparation Protocol Supervisor - example 0_0")
# # t.clear_steps
# # t.add_step("action", "object type", "object path", "data", "expected result")
# # qc.new_folder('something','subject\bond\case\add case')
# ensure
# qc.close
# end
#exporter = QCIntegration::QCExporter.new(QcSetting.first, $stdout)
class QCAutomation
def print_ole_methods(obj, output=nil)
output ||= @log
output.puts obj
if(!obj.is_a? String)
output.puts obj.ole_methods.collect{|m| "#{m}(#{m.params.join(', ')})"}.sort.uniq
end
end
def initialize(settings, log)
@settings = settings
@log = log
@folder_cache = {}
end
def open
#STDOUT.puts "opening QC connection to #{@settings.url} user:#{@settings.username}}"
STDOUT.flush
@tdc = WIN32OLE.new('TDApiOle80.TDConnection')
WIN32OLE.codepage = WIN32OLE::CP_UTF8
@tdc.InitConnectionEx(@settings.url)
@tdc.Login @settings.username, @settings.password
qcDomain = "DEFAULT"
qcProject = @settings.project
@tdc.Connect qcDomain, qcProject
@tdc
end
def find_or_add_test(path, test_name, test_type)
find_test_by_name(path, test_name) || add_test(path, test_name, test_type)
end
def add_test(path, test_name, test_type)
testF = get_test_factory(path)
test1 = testF.AddItem([test_name, test_type])
QCTest.new(test1, @tdc.ReqFactory, testF, @log, self)
end
def find_all_items
command = @tdc.command
command.CommandText = "select al_item_id, al_father_id, al_description from all_lists"
rec = command.Execute
list = []
until rec.EOR
list << [rec.FieldValue(0), rec.FieldValue(1), rec.FieldValue(2)]
rec.Next
end
list
end
def find_every_test
command = @tdc.command
command.CommandText = "select TS_TEST_ID, TS_NAME, TS_SUBJECT from TEST"
rec = command.Execute
list = []
until rec.EOR
list << [rec.FieldValue(0), rec.FieldValue(1), rec.FieldValue(2)]
rec.Next
end
list
end
def find_all_tests
command = @tdc.command
command.CommandText = "select TS_TEST_ID, TS_NAME, TS_SUBJECT from TEST WHERE TS_TYPE = 'VAPI-XP-TEST'"
rec = command.Execute
list = []
until rec.EOR
list << [rec.FieldValue(0), rec.FieldValue(1), rec.FieldValue(2)]
rec.Next
end
list
end
# Returns a hash of id(int) => TestFolder
def folders(refresh = false)
if @folders.nil? || refresh
@folders = Hash.new
find_all_items.each{|id, father_id, desc|
@folders[id.to_i] = TestFolder.new(id.to_i, father_id.to_i, desc, @folders)
}
end
@folders
end
def root_folder
folders.find{|k,v| v.father_id == -1 }[1]
end
def test_names(refresh = false)
if @tests.nil? || refresh
f = folders(refresh)
@tests = []
find_all_tests.each do |id, name, folder_id|
if f[folder_id.to_i]
@tests << "#{f[folder_id.to_i].path}#{name}"
else
@log.puts_error("Can't find folder #{folder_id}")
@tests << "Unattached/#{name}"
end
end
end
@tests
end
def find_test_by_name(path, name)
begin
@tdc.RefreshConnectionState
@log.puts_error "Lost Connection!!" if !@tdc.Connected
@log.puts_error "Logged out!!" if !@tdc.LoggedIn
testF = get_test_factory(path)
aFilter = testF.Filter
aFilter.setproperty("Filter","TS_NAME","\"#{name}\"")
#@log.puts "Filtering for '#{aFilter.Text}'"
testsList = testF.NewList(aFilter.Text)
testsList.Count > 0 ? QCTest.new(testsList.Item(1), @tdc.ReqFactory, testF, @log, self) : nil
rescue
@log.puts "ERROR: Failed to find test #{path}/#{name}"
nil
end
end
def find_test_by_id(id)
begin
@tdc.RefreshConnectionState
@log.puts_error "Lost Connection!!" if !@tdc.Connected
@log.puts_error "Logged out!!" if !@tdc.LoggedIn
testF = @tdc.TestFactory
aFilter = testF.Filter
aFilter.setproperty("Filter","TS_TEST_ID","#{id}")
testsList = testF.NewList(aFilter.Text)
testsList.Count > 0 ? QCTest.new(testsList.Item(1), @tdc.ReqFactory, testF, @log, self) : nil
rescue
@log.puts "ERROR: Failed to find test #{id}"
nil
end
end
def close
@tdc.Disconnect if @tdc.Connected
@tdc.Logout if @tdc.LoggedIn
@tdc.ReleaseConnection
end
def new_folder(folder_name, parent_folder)
treeM = @tdc.TreeManager
folder = treeM.NodeByPath(parent_folder)
item = folder.AddNode(folder_name)
item.Post
item
end
def download_automation_script
STDOUT.puts "download_automation_script"
objResourceFactory = @tdc.QCResourceFactory
objResourceFilter = objResourceFactory.Filter
objResourceFilter.setproperty("Filter","RSC_NAME","VapiScript")
objResourceList = objResourceFactory.NewList(objResourceFilter.Text)
objVapiScriptResource = objResourceList.item(1)
objVapiScriptResource.DownloadResource(QCTest.client_path, true)
objResourceFactory = nil
objResourceFilter = nil
objResourceList = nil
objVapiScriptResource = nil
end
def get_or_add_folder(path)
puts "Find or add : #{path}"
p = path.split(/[\/\\]/)
treeM = @tdc.TreeManager
folder = treeM.NodeByPath('subject')
p.each {|item| folder = (find_folder(item, folder) || add_folder(item,folder)) }
folder
end
private
def get_test_factory(path)
@folder_cache[path] ||= get_test_factory2(path)
@folder_cache[path]
end
def get_test_factory2(path)
folder = get_or_add_folder(path)
testF = folder.testFactory
end
def add_folder(folder_name, parent_folder)
@log.puts("add folder '#{folder_name}' - '#{parent_folder.inspect}'")
item = parent_folder.AddNode(folder_name)
item.Post
item
end
def find_folder(item, folder)
@log.puts("find folder '#{item}' - '#{folder.inspect}'")
begin
folder.FindChildNode(item)
rescue Exception
nil
end
end
end
end
module QCIntegration
class QCTest
def save
@test.Post if(@dirty)
end
def print_ole_methods(obj)
puts obj
if(!obj.is_a? String)
puts obj.ole_methods.collect{|m| "#{m}(#{m.params.join(', ')})"}.sort
end
end
def initialize(test, req_factory, test_factory, log, qc)
@qc = qc
@test = test
@req_factory = req_factory
@test_factory = test_factory
@log = log
@version_control = @test.VCS
@step_fieldmap = {}
@ds_factory = @test.DesignStepFactory
@ds_factory.Fields.each { |f| @step_fieldmap[f.Property().UserLabel()] = f.Name }
@test_fieldmap = {}
@test_factory.Fields.each { |f| @test_fieldmap[f.Property().UserLabel()] = f.Name }
@dirty = false
end
def check_out
if (!@checked_out && @version_control && !@version_control.IsCheckedOut)
@log.puts "checking out test"
begin
@version_control.CheckOut(-1, "checked out by automation", false)
@checked_out = @version_control.IsCheckedOut
rescue => e
puts e.inspect
@checked_out = true
end
end
@checked_out
end
def check_in(message)
save()
if (@checked_out && @version_control)
@log.puts "check in"
@version_control.CheckIn(nil, message, nil, nil)
@checked_out = false
end
end
def force_check_in(message)
save()
@log.puts "forced check in of test"
if (@version_control && @version_control.IsCheckedOut)
@version_control.CheckIn(nil, message, nil, nil)
@checked_out = false
end
end
def add_step(content)
content = {"Description" => content } unless( content.is_a? Hash)
@log.puts "add step"
begin
# @test.LockObject if !@test.IsLocked
check_out
step_num = @test.DesStepsNum
#Create the new design step
desStep = @ds_factory.AddItem(0)
desStep.setproperty("Field", @step_fieldmap["Step Name"] , "Step #{step_num}") if @step_fieldmap["Step Name"]
content.each{|k,v|
desStep.setproperty("Field", @step_fieldmap[k] , v) if @step_fieldmap[k]
}
# desStep.setproperty("Field", @step_fieldmap["Description"] , content) if @step_fieldmap["Description"]
# desStep.setproperty("Field", @step_fieldmap["Action"] ,action).to_s if @step_fieldmap["Action"]
# desStep.setproperty("Field", @step_fieldmap["Object Type"], object_type.to_s) if @step_fieldmap["Object Type"]
# desStep.setproperty("Field", @step_fieldmap["Object Path"], object_path.to_s) if @step_fieldmap["Object Path"]
# desStep.setproperty("Field", @step_fieldmap["Data"],data.to_s) if @step_fieldmap["Data"]
# desStep.setproperty("Field", @step_fieldmap["Expected Result"],expected_result.to_s) if @step_fieldmap["Expected Result"]
desStep.Post
ensure
check_in("Added steps")
end
end
def get_steps_content(fields = ["Description"])
content = []
list = @ds_factory.NewList("")
list.each {|step|
s = fields.map{|f|step.Field(@step_fieldmap[f])}
s = s[0] if s.length == 1
content << s
}
content
end
#######################################################################
# Generate a bunch of fields.
%w(status type description owner:TS_RESPONSIBLE subject).each do |meth|
accessor, field_name = meth.split(":")
field_name ||= "TS_#{meth.upcase}"
define_method(accessor+"=") { |value|
@test.setproperty("Field", field_name , value)
@dirty = true
}
define_method(accessor) {
@test.Field(field_name)
}
end
#######################################################################
def approver=(approver)
@test.setproperty("Field", @test_fieldmap["Approved by"] , approver)
@dirty = true
# @test.Post
end
def approver
@test.Field(@test_fieldmap["Approved by"])
end
def manualid=(manualid)
@test.setproperty("Field", @test_fieldmap["Automated Tests"] , manualid)
@dirty = true
# @test.Post
end
def manualid
@test.Field(@test_fieldmap["Automated Tests"])
end
def clear_steps
@log.puts "clear steps"
begin
check_out
list = @ds_factory.NewList("")
list.each {|step|
begin
@ds_factory.RemoveItem(step.ID)
rescue e
@log.puts "************can't delete step #{step.ID}"
end
}
ensure
check_in("Cleared steps")
end
end
def link_to_requirements(new_requirements)
@log.puts "link to requirements"
coverage_ids = requirements
(new_requirements - coverage_ids).each{|req| link_to_requirement(req)}
(coverage_ids - new_requirements).each{|req| unlink_requirement(req)}
end
def requirements
l = @test.GetCoverList()
(1..l.Count).map{|i| l.Item(i).ID} # to_a doesn't work
end
def link_to_requirement(requirement_id)
@log.puts "link to requirement"
begin
aReq = @req_factory.Item(requirement_id)
aReq.AddTestToCoverage @test.ID
aReq = nil
rescue => e
@log.puts "Error: failed to link requirement ##{requirement_id} to test #{@test.Name}"
@log.puts e.message
@log.puts e.backtrace
aReq = nil
end
end
def unlink_requirement(requirement_id)
@log.puts "unlink requirement"
begin
aReq = @req_factory.Item(requirement_id)
aReq.RemoveCoverage @test.ID
aReq = nil
rescue => e
@log.puts "Error: failed to unlink requirement ##{requirement_id} from test #{@test.Name}"
@log.puts e.message
@log.puts e.backtrace
aReq = nil
end
end
def unlink_all_requirements()
requirements.each{|req| unlink_requirement(req)}
end
def ID
@test.ID
end
def folder
#Note: Subject is already a Folder object as far as I can see, we should just wrap it.
@qc.folders[subject.NodeID.to_i]
end
def attach_template_files()
attach_template_files_in_folder(QCTest.client_path)
end
def attach_template_files_in_folder(folder)
@log.puts "storing files from #{folder}"
estore = @test.ExtendedStorage
estore.ClientPath = folder
estore.Save("*.*", true)
@dirty = true
# @test.Post
end
def name
@test.Name
end
def move(new_folder_id)
subject = new_folder_id
end
def self.client_path()
File.join(File.dirname(File.expand_path(__FILE__)),"template_files").gsub('/','\\')
end
# def method_missing(argc, *argv, &block)
# @log.puts "unknown method: #{argc}"
# @test.send(argc, *argv, &block)
# end
end
end
Copy link

ghost commented Apr 17, 2018

How to update result of test execution in QC for ruby selenium script ?
Please help .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment