trail_marker 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|