Last active
April 17, 2018 12:42
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$:.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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mklink /D %1 %2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to update result of test execution in QC for ruby selenium script ?
Please help .