trail_marker 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +71 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/testrail_marker.rb +44 -0
- data/exe/testrail_marker +45 -0
- data/lib/trail_marker/api_testrail.rb +364 -0
- data/lib/trail_marker/api_testrail_rev2.bak +350 -0
- data/lib/trail_marker/argument.rb +229 -0
- data/lib/trail_marker/config_file.rb +107 -0
- data/lib/trail_marker/mark_tests.rb +169 -0
- data/lib/trail_marker/request.rb +122 -0
- data/lib/trail_marker/response.rb +121 -0
- data/lib/trail_marker/results_parser.rb +241 -0
- data/lib/trail_marker/test.bak +12 -0
- data/lib/trail_marker/testrail.rb +106 -0
- data/lib/trail_marker/version.rb +3 -0
- data/lib/trail_marker.rb +17 -0
- metadata +133 -0
@@ -0,0 +1,169 @@
|
|
1
|
+
# Executes parsing and posting results to TestRail
|
2
|
+
class MarkTests
|
3
|
+
|
4
|
+
EXIT_MSG = "\nYour test results have been marked on TestRails!\n"
|
5
|
+
DEFAULT_COMMENT = "Marked by Automation"
|
6
|
+
|
7
|
+
#
|
8
|
+
def initialize(argobj, config_filename)
|
9
|
+
@argument = argobj
|
10
|
+
cf = ConfigFile.new(config_filename)
|
11
|
+
cf.check_create_configfile
|
12
|
+
@user = @argument.get_arg_value('-u') == '' ? cf.username : @argument.get_arg_value('-u')
|
13
|
+
@token = @argument.get_arg_value('-pw') == '' ? cf.token : @argument.get_arg_value('-pw')
|
14
|
+
@url = @argument.get_arg_value('-url') == '' ? cf.testrail_url : @argument.get_arg_value('-url')
|
15
|
+
@default_comment = @argument.get_arg_value('-com') == '' ? cf.default_comment : @argument.get_arg_value('-com')
|
16
|
+
puts "VALUES: #{@user} #{@token}"
|
17
|
+
end
|
18
|
+
|
19
|
+
# If user name and password (or token) are passed in the command line arguments
|
20
|
+
# it would use those instead of the preset values.
|
21
|
+
#
|
22
|
+
def get_client
|
23
|
+
client = TestRail::APIClient.new(@url)
|
24
|
+
client.user = @user
|
25
|
+
client.password = @token
|
26
|
+
return client
|
27
|
+
end
|
28
|
+
|
29
|
+
# Initial setup - creates API client and API testrail objects
|
30
|
+
#
|
31
|
+
def setup
|
32
|
+
if @client.nil? || @api_testrail.nil?
|
33
|
+
@client = get_client
|
34
|
+
@api_testrail = ApiTestRail.new(@client)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Determine if results are for a run or a plan.
|
40
|
+
# Calls method to mark results.
|
41
|
+
#
|
42
|
+
def markoff_all_results
|
43
|
+
mark_type = 'testrun'
|
44
|
+
runner = @argument.get_optional_arg(['-r', '-cr'])
|
45
|
+
if runner.nil? || runner == ""
|
46
|
+
mark_type = "testplan"
|
47
|
+
runner = @argument.get_optional_arg(['-t', '-ct'])
|
48
|
+
end
|
49
|
+
run_ids = []
|
50
|
+
project_id = @api_testrail.get_project_id(@argument.get_arg_value('-p'))
|
51
|
+
case mark_type
|
52
|
+
when "testrun"
|
53
|
+
run_name = @argument.get_optional_arg(['-r', '-cr'])
|
54
|
+
run_ids << @api_testrail.get_test_runplan_id(project_id, run_name)
|
55
|
+
when "testplan"
|
56
|
+
plan_name = @argument.get_optional_arg(['-t', '-ct'])
|
57
|
+
run_ids = @api_testrail.get_testplan_run_ids(project_id, plan_name)
|
58
|
+
end
|
59
|
+
markoff(run_ids, project_id)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Parses the XML files and makes API calls to post results to TestRail
|
63
|
+
def markoff(run_ids, pid = nil)
|
64
|
+
project_id = pid.nil? ? @api_testrail.get_project_id(@argument.get_arg_value('-p')) : pid
|
65
|
+
is_dir = @argument.arg_exists?('-x')
|
66
|
+
is_file = @argument.arg_exists?('-f')
|
67
|
+
if is_dir || is_file
|
68
|
+
results_parser = nil
|
69
|
+
#results_file = nil
|
70
|
+
if is_dir
|
71
|
+
results_parser = ResultsParser.new(@argument.get_arg_value('-x'))
|
72
|
+
results_files = results_parser.getAllXMLFiles()
|
73
|
+
else
|
74
|
+
specific_file = @argument.get_arg_value('-f')
|
75
|
+
results_parser = ResultsParser.new(specific_file)
|
76
|
+
results_files = Array.new
|
77
|
+
results_files << specific_file
|
78
|
+
end
|
79
|
+
|
80
|
+
if results_files.size <= 0
|
81
|
+
puts "No XML Results found. Please check your directory"
|
82
|
+
exit(0)
|
83
|
+
end
|
84
|
+
results_files.each do |one_file|
|
85
|
+
case_results = results_parser.read_XML_file(one_file)
|
86
|
+
if ! case_results.nil? && case_results.kind_of?(Array)
|
87
|
+
case_results.each do |one_case|
|
88
|
+
testrun_ids = []
|
89
|
+
testrun_ids += run_ids
|
90
|
+
markoff_test_case(@api_testrail, one_case, testrun_ids)
|
91
|
+
end
|
92
|
+
else
|
93
|
+
puts "No Results found in : #{one_file} (Might be empty)"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
def markoff_test_case(api_obj, result_hash, run_ids)
|
101
|
+
case_id = result_hash[:trail_case].gsub(/[Cc]/, "")
|
102
|
+
test_id = nil
|
103
|
+
run_id = nil
|
104
|
+
puts "=====> #{run_ids}"
|
105
|
+
if run_ids.size > 1
|
106
|
+
run_ids.each do |rid|
|
107
|
+
tempid = api_obj.get_testid(rid, case_id)
|
108
|
+
if ! tempid.nil?
|
109
|
+
test_id = tempid
|
110
|
+
run_id = rid
|
111
|
+
break
|
112
|
+
end
|
113
|
+
end
|
114
|
+
else
|
115
|
+
run_id = run_ids.pop()
|
116
|
+
end
|
117
|
+
passed = result_hash[:passed]
|
118
|
+
api_obj.markoff_test(case_id, run_id, passed, @default_comment)
|
119
|
+
end
|
120
|
+
|
121
|
+
def create_milestone
|
122
|
+
project_name = @argument.get_arg_value('-p')
|
123
|
+
milestone_name = @argument.get_arg_value('-m')
|
124
|
+
if ! milestone_name.nil?
|
125
|
+
@api_testrail.create_milestone(project_name, milestone_name)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# USER DOES NOT HAVE PERMISSION.
|
130
|
+
# Verify you have super user account or maybe
|
131
|
+
# not yet implemented in TestRail. GUI has no delete as well.
|
132
|
+
def delete_milestone
|
133
|
+
project_name = @argument.get_arg_value('-p')
|
134
|
+
milestone_name = @argument.get_arg_value('-dm')
|
135
|
+
if ! milestone_name.nil?
|
136
|
+
@api_testrail.delete_milestone(project_name, milestone_name)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def create_testrun
|
141
|
+
project_name = @argument.get_arg_value('-p')
|
142
|
+
milestone_name = @argument.get_optional_arg(['-m', '-cm'])
|
143
|
+
testrun_name = @argument.get_arg_value('-cr')
|
144
|
+
if ! testrun_name.nil?
|
145
|
+
@api_testrail.create_testrun(project_name, milestone_name, testrun_name)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def check_create
|
151
|
+
project_name = @argument.get_arg_value('-p')
|
152
|
+
if @argument.arg_exists?('-cm')
|
153
|
+
milestone_name = @argument.get_arg_value('-cm')
|
154
|
+
@api_testrail.create_milestone(project_name, milestone_name)
|
155
|
+
end
|
156
|
+
run_name = @argument.get_arg_value('-cr')
|
157
|
+
if @argument.arg_exists?('-cr')
|
158
|
+
milestone_name = @argument.get_optional_arg(['-m', '-cm'])
|
159
|
+
suite_name = @argument.get_arg_value('-s')
|
160
|
+
@api_testrail.create_testrun(project_name, milestone_name, run_name, suite_name)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def show_exit_msg
|
165
|
+
puts "\n#{EXIT_MSG}\n"
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require_relative 'testrail'
|
2
|
+
|
3
|
+
# Calls testrail API
|
4
|
+
# History: 2/26/18 Removed retry for failed calls
|
5
|
+
# 2/27/18 Combined post/get methods DRY
|
6
|
+
# Change retry to skip only if TC not found.
|
7
|
+
#
|
8
|
+
class Request
|
9
|
+
RETRIES = 1
|
10
|
+
|
11
|
+
def initialize(client, debug_mode = false)
|
12
|
+
@client = client
|
13
|
+
@debug_mode = get_debug_value(debug_mode)
|
14
|
+
@debug_mode = true
|
15
|
+
end
|
16
|
+
|
17
|
+
# Retries an API call max number of times if an
|
18
|
+
# exception is raised. Sleeps 4, 8, 12 .... seconds
|
19
|
+
# for each retry.
|
20
|
+
#
|
21
|
+
def exec_api_call(rest_type, req, data = nil, exit_on_fail = false)
|
22
|
+
max_retry = RETRIES
|
23
|
+
get_hash = nil
|
24
|
+
attempts = 0
|
25
|
+
is_good = false
|
26
|
+
while !is_good && attempts < max_retry
|
27
|
+
attempts += 1
|
28
|
+
get_hash = call_api(req, rest_type, data)
|
29
|
+
is_good = get_hash[:status]
|
30
|
+
unless is_good
|
31
|
+
exit_script() if exit_on_fail
|
32
|
+
puts "Got Error making API call - #{req} "
|
33
|
+
if attempts < max_retry
|
34
|
+
puts "Retrying #{attempts}"
|
35
|
+
sleep(4 * attempts)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
get_hash
|
40
|
+
end
|
41
|
+
|
42
|
+
# TODO: DRY with exec_get
|
43
|
+
def exec_post(req, data, exit_on_fail = false)
|
44
|
+
response_hash = exec_api_call('POST', req, data, exit_on_fail)
|
45
|
+
response_hash[:response]
|
46
|
+
end
|
47
|
+
|
48
|
+
def exec_get(req, exit_on_fail = false)
|
49
|
+
response_hash = exec_api_call('GET', req, nil, exit_on_fail)
|
50
|
+
check_authentication_fail(response_hash) unless response_hash[:status]
|
51
|
+
response_hash[:response]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Executes a TestRail API call but catches any
|
55
|
+
# exception raised to prevent script from crashing.
|
56
|
+
# Used by exec_get to do retries.
|
57
|
+
#
|
58
|
+
def call_api(req, rtype, data=nil)
|
59
|
+
msg("#{rtype} REQ: #{req}")
|
60
|
+
res_hash = {:status => true, :response => ""}
|
61
|
+
begin
|
62
|
+
if rtype == 'POST'
|
63
|
+
get_response = @client.send_post(req, data)
|
64
|
+
else
|
65
|
+
get_response = @client.send_get(req)
|
66
|
+
end
|
67
|
+
rescue Exception => e
|
68
|
+
puts "Raised Exception: #{e.message}."
|
69
|
+
res_hash[:status] = false
|
70
|
+
res_hash[:response] = e.message
|
71
|
+
else
|
72
|
+
res_hash[:status] = true
|
73
|
+
res_hash[:response] = get_response
|
74
|
+
end
|
75
|
+
msg("RESPONSE: #{res_hash}")
|
76
|
+
return res_hash
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def exit_script()
|
82
|
+
msg("Exiting script.")
|
83
|
+
exit(1)
|
84
|
+
end
|
85
|
+
|
86
|
+
def msg(msg_txt)
|
87
|
+
if @debug_mode
|
88
|
+
puts msg_txt
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class APIError < StandardError
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_debug_value(debug_val)
|
96
|
+
boolval = false
|
97
|
+
if !! debug_val == debug_val
|
98
|
+
boolval = debug_val
|
99
|
+
else
|
100
|
+
boolval = string_to_boolean(debug_val)
|
101
|
+
end
|
102
|
+
return boolval
|
103
|
+
end
|
104
|
+
|
105
|
+
def string_to_boolean(strval)
|
106
|
+
retval = false
|
107
|
+
if strval.downcase == "true"
|
108
|
+
retval = true
|
109
|
+
end
|
110
|
+
return retval
|
111
|
+
end
|
112
|
+
|
113
|
+
def check_authentication_fail(response_hash)
|
114
|
+
failed_str = "Authentication failed"
|
115
|
+
max_attempts_str = "maximum number of failed"
|
116
|
+
if response_hash[:response].include?(failed_str) || response_hash[:response].include?(max_attempts_str)
|
117
|
+
puts "Cannot authenticate User or password.\n"
|
118
|
+
exit(1)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
# Holds the TestRail response to easily access fields and
|
4
|
+
# give an easy user selector.
|
5
|
+
# TODO: Clean this UP!
|
6
|
+
class Response
|
7
|
+
|
8
|
+
@response_type = nil
|
9
|
+
|
10
|
+
def initialize(response)
|
11
|
+
@response_type = response.class.name
|
12
|
+
@json_data = ""
|
13
|
+
@raw_data = response
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(response)
|
17
|
+
initialize(response)
|
18
|
+
end
|
19
|
+
|
20
|
+
def list_projects()
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_value(key)
|
25
|
+
retval = nil
|
26
|
+
case @response_type
|
27
|
+
when "Array"
|
28
|
+
retval = parse_array(@raw_data, key)
|
29
|
+
when "Hash"
|
30
|
+
retval = parse_hash(@raw_data, key)
|
31
|
+
end
|
32
|
+
return retval
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_id(key, value)
|
36
|
+
retval = nil
|
37
|
+
case @response_type
|
38
|
+
when "Array"
|
39
|
+
retval = parse_array_kv(@raw_data, key, value, 'id')
|
40
|
+
when "Hash"
|
41
|
+
retval = @raw_data['id']
|
42
|
+
end
|
43
|
+
return retval
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns ID of item selected via user key enter
|
47
|
+
#
|
48
|
+
def picker(key)
|
49
|
+
min_val = 1
|
50
|
+
max_val = 1
|
51
|
+
valarr = get_value(key)
|
52
|
+
puts "Options Available: "
|
53
|
+
valarr.each_with_index do |one_select, index|
|
54
|
+
dis_index = index + 1
|
55
|
+
puts "#{dis_index}) #{one_select}"
|
56
|
+
max_val = dis_index
|
57
|
+
end
|
58
|
+
|
59
|
+
puts "q) TO QUIT"
|
60
|
+
print "Enter number of your selection: "
|
61
|
+
|
62
|
+
user_choice = pick_filter(min_val, max_val, true)
|
63
|
+
puts "You SELECTED #{valarr[user_choice - 1]}"
|
64
|
+
puts ""
|
65
|
+
return valarr[user_choice - 1]
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def parse_array_kv(rdata, k, v, key_return)
|
71
|
+
fnd = rdata.detect {|unhash| unhash[k] == v}
|
72
|
+
return fnd['id']
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse_array(rdata, key)
|
76
|
+
retarr = []
|
77
|
+
rdata.map do |h|
|
78
|
+
retarr.push(h[key])
|
79
|
+
end
|
80
|
+
return retarr
|
81
|
+
end
|
82
|
+
|
83
|
+
def parse_hash(rdata, key)
|
84
|
+
retval = rdata[key]
|
85
|
+
end
|
86
|
+
|
87
|
+
# TODO: Add user keyboard input checks.
|
88
|
+
#
|
89
|
+
def pick_filter(min, max, add_quit = true)
|
90
|
+
guide_msg = "Valid values are from #{min} to #{max}"
|
91
|
+
if add_quit
|
92
|
+
guide_msg += " or 'q' to quit"
|
93
|
+
end
|
94
|
+
retval = nil
|
95
|
+
entered_valid = false
|
96
|
+
atmps = 0
|
97
|
+
integer_pattern = /[0-9]+/
|
98
|
+
while ! entered_valid do
|
99
|
+
user_input = $stdin.gets.chomp.downcase
|
100
|
+
if (user_input == 'q' && add_quit) || (atmps > 7)
|
101
|
+
puts "Exiting!"
|
102
|
+
exit(0)
|
103
|
+
end
|
104
|
+
if user_input =~ integer_pattern
|
105
|
+
entered_value = user_input.to_i
|
106
|
+
if entered_value >= min && entered_value <= max
|
107
|
+
retval = entered_value
|
108
|
+
entered_valid = true
|
109
|
+
end
|
110
|
+
end
|
111
|
+
if ! entered_valid
|
112
|
+
puts guide_msg
|
113
|
+
end
|
114
|
+
atmps += 1
|
115
|
+
end
|
116
|
+
return retval
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# HISTORY: 1/7/2016 modified to handle just 1 file
|
5
|
+
# 3/21/2016 Allows indexing of test case
|
6
|
+
# e.g. (TestRail: [C11, C22], [C33, C44], 1) Last argument is an index (starts at 0)
|
7
|
+
# to mark test case C33 and C44. Modified method parse_trail_tag to implement this.
|
8
|
+
#
|
9
|
+
# TODO: Parse Failure element CDATA to add to comment - will require changes in request.rb, etc.
|
10
|
+
#
|
11
|
+
class ResultsParser
|
12
|
+
|
13
|
+
DEBUG_MODE = false
|
14
|
+
|
15
|
+
def initialize(results_path)
|
16
|
+
checkIfDirectoryExists(results_path)
|
17
|
+
@results_path = results_path
|
18
|
+
#xmls = getAllXMLFiles(results_path)
|
19
|
+
#readAllXMLFiles(xmls)
|
20
|
+
end
|
21
|
+
|
22
|
+
def checkIfDirectoryExists(xml_loc)
|
23
|
+
if ! File.directory?(xml_loc) && ! File.file?(xml_loc)
|
24
|
+
puts "ERROR: Cannot find the XML results directory or file:"
|
25
|
+
puts " #{xml_loc}"
|
26
|
+
puts " Please check the path of the directory where the results are located.\n\n"
|
27
|
+
exit(1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Retrieves all .xml files in the directory passed as parameter
|
32
|
+
# also recurssively gets subdirectory files because it uses Dir.glob
|
33
|
+
# Return: array of file names with path where it is located.
|
34
|
+
def getAllXMLFiles()
|
35
|
+
originalDir = Dir.pwd
|
36
|
+
Dir.chdir @results_path
|
37
|
+
filesArray = Array.new
|
38
|
+
debug_msg "#{@results_path}/**/*.xml"
|
39
|
+
Dir.glob("**/*.xml") do |f|
|
40
|
+
debug_msg "XML: #{f}"
|
41
|
+
filesArray << "#{@results_path}/" + f
|
42
|
+
end
|
43
|
+
Dir.chdir originalDir
|
44
|
+
return filesArray
|
45
|
+
end
|
46
|
+
|
47
|
+
def readAllXMLFiles(xml_files)
|
48
|
+
xml_files.each do |xml_file|
|
49
|
+
read_XML_file(xml_file)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Reads XML file and uses nokogiri to parse
|
54
|
+
#
|
55
|
+
def read_XML_file(xfile)
|
56
|
+
result_array = []
|
57
|
+
if File.file?(xfile)
|
58
|
+
puts "\n\nOPENING #{xfile}"
|
59
|
+
f = File.open(xfile)
|
60
|
+
doc = Nokogiri::XML(f)
|
61
|
+
if is_squish?(doc)
|
62
|
+
result_array = squish_parser(doc)
|
63
|
+
else
|
64
|
+
result_array = rspec_parser(doc)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
puts "\nNot a file: #{xfile} - verify options (-x for directory, -f for a specific file)"
|
68
|
+
end
|
69
|
+
return result_array
|
70
|
+
end
|
71
|
+
|
72
|
+
# Parses the SquishReport XML results file
|
73
|
+
def squish_parser(nokigiri_doc)
|
74
|
+
result_arr = []
|
75
|
+
verifications = nokigiri_doc.xpath("//verification")
|
76
|
+
verifications.each do |verification|
|
77
|
+
#puts "ONEVER: #{verification}"
|
78
|
+
trail_cases = parse_trail_tag(verification["name"])
|
79
|
+
result = verification.xpath("result").first
|
80
|
+
is_passed = squish_check_passed(result)
|
81
|
+
debug_msg "\nVERIFICATION: #{verification["name"]} :: #{trail_cases}"
|
82
|
+
trail_cases = parse_trail_tag(verification["name"])
|
83
|
+
trail_cases.each do |trail_case|
|
84
|
+
result_arr.push({:trail_case => trail_case, :passed => is_passed})
|
85
|
+
end
|
86
|
+
end
|
87
|
+
debug_msg "Squish FINAL: #{result_arr}"
|
88
|
+
return result_arr
|
89
|
+
end
|
90
|
+
|
91
|
+
# Parses the results of an RSPEC XML file.
|
92
|
+
# TODO:
|
93
|
+
def rspec_parser(nokigiri_doc)
|
94
|
+
result_arr = []
|
95
|
+
testsuites = nokigiri_doc.xpath("//testsuites")
|
96
|
+
testsuites.each do |suites|
|
97
|
+
testsuite = suites.xpath("./testsuite")
|
98
|
+
testsuite.each do |suite|
|
99
|
+
debug_msg "\nSUITE: #{suite["name"]} "
|
100
|
+
testsuite_name = suite["name"]
|
101
|
+
testcases = suite.xpath("./testcase")
|
102
|
+
testcases.each do |tcase|
|
103
|
+
debug_msg "TESTCASE: #{tcase}"
|
104
|
+
is_passed = false
|
105
|
+
failure = tcase.xpath("./failure")
|
106
|
+
if ! failure.nil?
|
107
|
+
is_passed = true
|
108
|
+
if failure.size > 0
|
109
|
+
is_passed = false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
debug_msg " TC: #{tcase["name"]}"
|
113
|
+
testcase_name = tcase["name"]
|
114
|
+
trail_cases = parse_trail_tag(testcase_name)
|
115
|
+
trail_cases.each do |trail_case|
|
116
|
+
result_arr.push({:trail_case => trail_case, :passed => is_passed})
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
debug_msg "FINAL: #{result_arr}"
|
121
|
+
return result_arr
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Parses the 'name' attribute of <testcase> and returns all
|
126
|
+
# test cases found. Returns an array in case a single test can mark off multiple test cases.
|
127
|
+
# Ex. <testcase name="Login: should allow all valued users to successfully login (TestRail: C123, C888)
|
128
|
+
# Returns ['C123', 'C888']
|
129
|
+
def parse_trail_tag(name_line)
|
130
|
+
case_arr = []
|
131
|
+
ndex = get_index(name_line)
|
132
|
+
if ndex < 0
|
133
|
+
pattern = /\(TestRail:([Cc0-9\,\s]+)\)/
|
134
|
+
just_cases = pattern.match(name_line)
|
135
|
+
if ! just_cases.nil?
|
136
|
+
debug_msg "HowMany #{just_cases[1]}"
|
137
|
+
split_cases = just_cases[1].split(',')
|
138
|
+
split_cases.each do |onecase|
|
139
|
+
case_arr.push(onecase.strip)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
debug_msg "ARR: #{case_arr}"
|
143
|
+
else
|
144
|
+
case_arr = get_indexed_cases(name_line, ndex)
|
145
|
+
end
|
146
|
+
return case_arr
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
# Called if the test cases are indexed as described in JIRA ticket ACI-206
|
152
|
+
#
|
153
|
+
def get_indexed_cases(name_line, nx)
|
154
|
+
cases = []
|
155
|
+
pattern = /\(TestRail:([Cc0-9\,\s\[\]\|]+)\:[0-9\s]+\)/
|
156
|
+
just_cases = pattern.match(name_line)
|
157
|
+
if ! just_cases.nil?
|
158
|
+
case_tags = just_cases[1]
|
159
|
+
debug_msg "PARSING: #{case_tags}"
|
160
|
+
if (case_tags =~ /^\s*[Cc0-9\,\s]+$/)
|
161
|
+
debug_msg "CASE COMMAS"
|
162
|
+
indexed_case = case_tags.split(',')[nx].strip
|
163
|
+
cases.push(indexed_case)
|
164
|
+
elsif (case_tags =~ /^\s*[Cc0-9\,\s\|]+$/)
|
165
|
+
debug_msg "CASE PIPES"
|
166
|
+
indexed_case = case_tags.split('|')[nx]
|
167
|
+
cases = strip_array(indexed_case.split(','))
|
168
|
+
elsif (case_tags =~ /^\s*[Cc0-9\,\s\[\]]+$/)
|
169
|
+
debug_msg "CASE BRACKETS"
|
170
|
+
subed_tags = sub_brackets(case_tags)
|
171
|
+
indexed_case = subed_tags.split('|')[nx]
|
172
|
+
cases = strip_array(indexed_case.split(','))
|
173
|
+
end
|
174
|
+
end
|
175
|
+
return cases
|
176
|
+
end
|
177
|
+
|
178
|
+
# Replaces ],[ and ], and ,[ with '|'
|
179
|
+
def sub_brackets(nline)
|
180
|
+
local_line = nline
|
181
|
+
local_line.gsub!(/\]\s*\,\s*\[/, '|')
|
182
|
+
local_line.gsub!(/\]\s*\,/, '|')
|
183
|
+
local_line.gsub!(/\,\s*\[/, '|')
|
184
|
+
return local_line.tr('[]', '')
|
185
|
+
end
|
186
|
+
|
187
|
+
# Parses for (TestRail: [C12, C13], [C21, C24], [C33]:2)
|
188
|
+
# Returns the index number if found or -1 if not found
|
189
|
+
def get_index(name_line)
|
190
|
+
index_found = -1
|
191
|
+
pattern = /\(TestRail:.*\:\s*([0-9]+)\s*\)/
|
192
|
+
just_cases = pattern.match(name_line)
|
193
|
+
if ! just_cases.nil?
|
194
|
+
index_found = just_cases[1].to_i
|
195
|
+
end
|
196
|
+
return index_found
|
197
|
+
end
|
198
|
+
|
199
|
+
def is_squish?(nokigiri_doc)
|
200
|
+
retval = false
|
201
|
+
squish_report = nokigiri_doc.xpath("/SquishReport")
|
202
|
+
if ! squish_report.nil?
|
203
|
+
if squish_report.size > 0
|
204
|
+
retval = true
|
205
|
+
end
|
206
|
+
end
|
207
|
+
return retval
|
208
|
+
end
|
209
|
+
|
210
|
+
def squish_check_passed(result_doc)
|
211
|
+
retval = false
|
212
|
+
if ! result_doc.nil?
|
213
|
+
debug_msg "RESULT: #{result_doc}"
|
214
|
+
get_type = result_doc['type']
|
215
|
+
if get_type.downcase == "pass"
|
216
|
+
retval = true
|
217
|
+
end
|
218
|
+
end
|
219
|
+
debug_msg "PASED: #{retval}"
|
220
|
+
return retval
|
221
|
+
end
|
222
|
+
|
223
|
+
# Removed all white spaces before/after each cell in
|
224
|
+
# an array. Returns array.
|
225
|
+
def strip_array(clothed_arr)
|
226
|
+
fully_stripped = []
|
227
|
+
clothed_arr.each do |onecase|
|
228
|
+
fully_stripped.push(onecase.strip)
|
229
|
+
end
|
230
|
+
return fully_stripped
|
231
|
+
end
|
232
|
+
|
233
|
+
def debug_msg(msg)
|
234
|
+
if DEBUG_MODE
|
235
|
+
puts msg
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
|