cukerail 0.2.2 → 0.3.0
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 +4 -4
- data/Rakefile +1 -1
- data/lib/cukerail/version.rb +1 -1
- data/lib/json_sender.rb +171 -0
- data/lib/tasks/cukerail.rake +71 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d5e94039d69eaeda30dcd54079c8a6a32e54405
|
4
|
+
data.tar.gz: 5de856db7882e048d153b3363d4416747e7c399d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cee48c1ec2d56dc332dccd445fde07232d67a7a9c419fce54f4e241e2e2ee0cb42f58b07883cb966bfd211be9ddbdeb26c30c959fe402db1da9534f7df1a77d
|
7
|
+
data.tar.gz: 8981b323ad57e7d668c304f9433f45ecb474ebf9ef11e7eab0a19b933c61bfbf8b5c500899f6128feba6c9bdccfe53d7b19479ae39f8f4e0f7697cee3133b531
|
data/Rakefile
CHANGED
data/lib/cukerail/version.rb
CHANGED
data/lib/json_sender.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
require_relative "cukerail/version"
|
2
|
+
require_relative "cukerail/testrail"
|
3
|
+
require 'json' unless JSON
|
4
|
+
module Cukerail
|
5
|
+
class JsonSender
|
6
|
+
attr_reader :testrail_api_client,:results
|
7
|
+
def initialize(json_file)
|
8
|
+
if %w(BASE_URL USER PASSWORD).map{|e| ENV["TESTRAIL_#{e}"]}.any?{|e| e=='' || !e}
|
9
|
+
raise 'You need to setup Testrail environment parameters see https://bbcworldwide.atlassian.net/wiki/display/BAR/Installing+and+Running+Cukerail'
|
10
|
+
end
|
11
|
+
@testrail_api_client = TestRail::APIClient.new(ENV['TESTRAIL_BASE_URL'],ENV['TESTRAIL_USER'],ENV['TESTRAIL_PASSWORD'])
|
12
|
+
@results = JSON.parse(File.read(json_file)).select{|f| f['tags']}
|
13
|
+
end
|
14
|
+
|
15
|
+
def each_feature
|
16
|
+
results.each do |feature|
|
17
|
+
scenarios = feature['elements'].reject{|e| e['keyword']=='Background'}.select{|e| e['type'] == 'scenario'}
|
18
|
+
project_id,suite_id,sub_section_id,background_steps = extract_top_level_data(feature)
|
19
|
+
yield scenarios,project_id,suite_id,sub_section_id,background_steps
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def get_id(scenario,background_steps,project_id,suite_id,sub_section_id)
|
25
|
+
title = get_name(scenario)
|
26
|
+
found_case = testrail_api_client.send_get("get_cases/#{project_id}&suite_id=#{suite_id}").select{|c| c['title'] == title}.first
|
27
|
+
if found_case
|
28
|
+
result= found_case['id']
|
29
|
+
else
|
30
|
+
result = create_new_case(scenario,background_steps,project_id,suite_id,sub_section_id)['id']
|
31
|
+
end
|
32
|
+
return result
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract_top_level_data(feature)
|
36
|
+
project_id = feature['tags'].select{|j| j['name']=~/project_\d+/}.map{|j| /project_(\d+)/.match(j['name'])[1].to_i}.first
|
37
|
+
suite_id = feature['tags'].select{|j| j['name']=~/suite_\d+/}.map{|j| /suite_(\d+)/.match(j['name'])[1].to_i}.first
|
38
|
+
sub_section_id = feature['tags'].select{|j| j['name']=~/sub_section_\d+/}.map{|j| /sub_section_(\d+)/.match(j['name'])[1].to_i}.first
|
39
|
+
background=feature['elements'].select{|e| e['keyword']=='Background'}.first
|
40
|
+
background_steps = background['steps'].map{|s| s['keyword']+s['name']}.join("\n")
|
41
|
+
return project_id,suite_id,sub_section_id,background_steps
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_name(scenario)
|
45
|
+
base_name = scenario['name']
|
46
|
+
outline_number_str = scenario['id'].split(';').select{|e| e =~/^\d+$/}.first
|
47
|
+
if outline_number_str
|
48
|
+
outline_number = (outline_number_str.to_i) -1
|
49
|
+
end
|
50
|
+
tags= [scenario['tags']].flatten.compact
|
51
|
+
requirement = tags.select{|t| t['name'] =~/@req/}.map{|t| /@req_(\w+)/.match(t['name'])[1]}.first unless tags.empty?
|
52
|
+
[requirement, base_name, outline_number].join(' ').strip
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_new_case(scenario,background_steps,project_id,suite_id,sub_section_id)
|
56
|
+
data = prepare_data(scenario,background_steps)
|
57
|
+
testrail_api_client.send_post("add_case/#{sub_section_id || suite_id}", data)
|
58
|
+
end
|
59
|
+
|
60
|
+
def send_steps(scenario,background_steps,testcase_id)
|
61
|
+
data = prepare_data(scenario,background_steps)
|
62
|
+
testrail_api_client.send_post("update_case/#{testcase_id}",data)
|
63
|
+
end
|
64
|
+
|
65
|
+
def prepare_data(scenario,background_steps)
|
66
|
+
steps = background_steps + "\n" + scenario['steps'].map{|s| s['keyword']+s['name']}.join("\n")
|
67
|
+
is_manual = scenario['tags'].any?{|tag| tag['name'] =~/manual/} if scenario['tags']
|
68
|
+
data = {'title'=>get_name(scenario),
|
69
|
+
'type_id'=>(is_manual ? 7 : 1 ),
|
70
|
+
'custom_steps'=>steps,
|
71
|
+
'refs'=>defects(scenario)
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def defects(scenario)
|
76
|
+
if scenario['tags']
|
77
|
+
scenario['tags'].select{|t| t['name'] =~/@jira_/}.map{|t| /jira_(\w+-\w+)/.match(t['name'])}.join(' ')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def send_result(scenario,id,testrun)
|
82
|
+
error_line = scenario['steps'].select{|s| s['result']['status'] != 'passed'}.first
|
83
|
+
if error_line
|
84
|
+
puts error_line['result']
|
85
|
+
testrail_status = case error_line['result']['status']
|
86
|
+
when 'failed'
|
87
|
+
{id:5,comment: 'failed'}
|
88
|
+
when 'undefined'
|
89
|
+
{id:7,comment: 'undefined step'}
|
90
|
+
when 'pending'
|
91
|
+
{id:6,comment: 'pending step'}
|
92
|
+
when 'skipped'
|
93
|
+
{id:5,comment: 'failed in before hook'}
|
94
|
+
end
|
95
|
+
error_result = error_line['error_message']
|
96
|
+
failure_message = <<-FAILURE
|
97
|
+
Error message: #{testrail_status[:comment]} #{error_result}
|
98
|
+
Step: #{error_line['keyword']} #{error_line['name']}
|
99
|
+
Location: #{error_line['match']['location']}
|
100
|
+
FAILURE
|
101
|
+
else
|
102
|
+
testrail_status = {id:1,comment: 'passed'}
|
103
|
+
failure_message = nil
|
104
|
+
end
|
105
|
+
report_on_result = {status_id:testrail_status[:id],comment:failure_message,defects:defects(scenario)}
|
106
|
+
begin
|
107
|
+
testrail_api_client.send_post("add_result_for_case/#{testrun}/#{id}",report_on_result)
|
108
|
+
rescue => e
|
109
|
+
if e.message =~ /No \(active\) test found for the run\/case combination/
|
110
|
+
add_case_to_test_run(id,testrun)
|
111
|
+
retry
|
112
|
+
else
|
113
|
+
puts "#{e.message} testrun=#{testrun} test case id=#{id}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_run(run_id)
|
119
|
+
testrail_api_client.send_get("get_run/#{run_id}")
|
120
|
+
end
|
121
|
+
|
122
|
+
def get_tests_in_a_run(run_id)
|
123
|
+
testrail_api_client.send_get("get_tests/#{run_id}")
|
124
|
+
end
|
125
|
+
|
126
|
+
def update_run(testrun,case_ids)
|
127
|
+
begin
|
128
|
+
testrail_api_client.send_post("update_run/#{testrun}",case_ids)
|
129
|
+
rescue => e
|
130
|
+
puts "#{e.message} testrun=#{testrun} test case ids=#{case_ids}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def remove_case_from_test_run(testcase,testrun)
|
135
|
+
testcase_id = get_id(testcase)
|
136
|
+
run = get_run(testrun)
|
137
|
+
unless run['include_all']
|
138
|
+
case_ids = get_tests_in_a_run(testrun).map{|h| h['case_id']} - [testcase_id]
|
139
|
+
update_run(testrun,{'case_ids'=>case_ids})
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def add_case_to_test_run(testcase_id,testrun)
|
144
|
+
run = get_run(testrun)
|
145
|
+
unless run['include_all']
|
146
|
+
case_ids = get_tests_in_a_run(testrun).map{|h| h['case_id']} + [testcase_id]
|
147
|
+
update_run(testrun,{'case_ids'=>case_ids})
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def remove_all_except_these_cases_from_testrun(testcases,testrun)
|
152
|
+
run = get_run(testrun)
|
153
|
+
unless run['include_all']
|
154
|
+
case_ids = get_tests_in_a_run(testrun).map{|h| h['case_id']} & testcases
|
155
|
+
update_run(testrun,{'case_ids'=>case_ids})
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def remove_all_except_these_cases_from_suite(testcases,project_id,suite_id)
|
160
|
+
puts '=== testcases === '
|
161
|
+
puts testcases
|
162
|
+
existing_cases = testrail_api_client.send_get("get_cases/#{project_id}&suite_id=#{suite_id}").map{|m| m['id']}
|
163
|
+
puts '===== existing_cases === '
|
164
|
+
puts existing_cases
|
165
|
+
(existing_cases - testcases).each do |case_to_remove|
|
166
|
+
puts "case_to_remove #{case_to_remove}"
|
167
|
+
testrail_api_client.send_post("delete_case/#{case_to_remove}",nil)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative '../json_sender'
|
2
|
+
desc 'load a json results file into a test suite'
|
3
|
+
task :load_to_suite do
|
4
|
+
raise 'You must have JSON=filename on the command line' unless ENV['JSON']
|
5
|
+
json_sender =Cukerail::JsonSender.new(ENV['JSON'])
|
6
|
+
features = json_sender.results
|
7
|
+
#only work with feature files that have tags set up
|
8
|
+
features.select{|f| f['tags']}.each do | feature |
|
9
|
+
# project_id = feature['tags'].select{|j| j['name']=~/project_\d+/}.map{|j| /project_(\d+)/.match(j['name'])[1].to_i}.first
|
10
|
+
# suite_id = feature['tags'].select{|j| j['name']=~/suite_\d+/}.map{|j| /suite_(\d+)/.match(j['name'])[1].to_i}.first
|
11
|
+
# sub_section_id = feature['tags'].select{|j| j['name']=~/sub_section_\d+/}.map{|j| /sub_section_(\d+)/.match(j['name'])[1].to_i}.first
|
12
|
+
# background=feature['elements'].select{|e| e['keyword']=='Background'}.first
|
13
|
+
# background_steps = background['steps'].map{|s| s['keyword']+s['name']}.join("\n")
|
14
|
+
project_id,suite_id,sub_section_id,background_steps = json_sender.extract_top_level_data(feature)
|
15
|
+
feature['elements'].reject{|e| e['keyword']=='Background'}.select{|e| e['type'] == 'scenario'}.each do | scenario |
|
16
|
+
testcase_id = json_sender.get_id(scenario,background_steps,project_id,suite_id,sub_section_id) if scenario['type'] == 'scenario'
|
17
|
+
puts "testcase_id = #{testcase_id}"
|
18
|
+
json_sender.send_steps(scenario,background_steps,testcase_id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'load a json results file into a test run'
|
24
|
+
task :load_to_test_run do
|
25
|
+
raise 'You must have TESTRUN=testrun_number on the command line' unless ENV['TESTRUN']
|
26
|
+
json_sender =Cukerail::JsonSender.new(ENV['JSON'])
|
27
|
+
#only work with feature files that have tags set up
|
28
|
+
json_sender.each_feature do | scenarios,project_id,suite_id,sub_section_id,background_steps |
|
29
|
+
scenarios.each do | scenario |
|
30
|
+
testcase_id = json_sender.get_id(scenario,background_steps,project_id,suite_id,sub_section_id)
|
31
|
+
puts "scenario_id #{scenario['id']} testcase_id = #{testcase_id}"
|
32
|
+
json_sender.send_steps(scenario,background_steps,testcase_id)
|
33
|
+
json_sender.send_result(scenario,testcase_id,ENV['TESTRUN'])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "remove cases from a test run that are aren't in the json results"
|
39
|
+
task :remove_from_test_run do
|
40
|
+
raise 'You must have TESTRUN=testrun_number on the command line' unless ENV['TESTRUN']
|
41
|
+
raise 'You must have JSON=filename on the command line' unless ENV['JSON']
|
42
|
+
json_sender =Cukerail::JsonSender.new(ENV['JSON'])
|
43
|
+
testcase_ids = []
|
44
|
+
json_sender.each_feature do | scenarios,project_id,suite_id,sub_section_id,background_steps |
|
45
|
+
scenarios.each do | scenario |
|
46
|
+
testcase_ids << json_sender.get_id(scenario,background_steps,project_id,suite_id,sub_section_id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
json_sender.remove_all_except_these_cases_from_testrun(testcase_ids,ENV['TESTRUN'])
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "match test run cases to json results file"
|
53
|
+
task match_to_test_run: [:remove_from_test_run,:load_to_test_run] do
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "remove cases from a test suite that aren't in the json results"
|
57
|
+
task :remove_from_test_suite do
|
58
|
+
raise 'You must have JSON=filename on the command line' unless ENV['JSON']
|
59
|
+
json_sender =Cukerail::JsonSender.new(ENV['JSON'])
|
60
|
+
testcase_ids = []
|
61
|
+
ex_project_id = 0
|
62
|
+
ex_suite_id = 0
|
63
|
+
json_sender.each_feature do | scenarios,project_id,suite_id,sub_section_id,background_steps |
|
64
|
+
ex_project_id = project_id
|
65
|
+
ex_suite_id = suite_id
|
66
|
+
scenarios.each do | scenario |
|
67
|
+
testcase_ids << json_sender.get_id(scenario,background_steps,project_id,suite_id,sub_section_id)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
json_sender.remove_all_except_these_cases_from_suite(testcase_ids,ex_project_id,ex_suite_id)
|
71
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cukerail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Small
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -98,6 +98,8 @@ files:
|
|
98
98
|
- lib/cukerail.rb
|
99
99
|
- lib/cukerail/testrail.rb
|
100
100
|
- lib/cukerail/version.rb
|
101
|
+
- lib/json_sender.rb
|
102
|
+
- lib/tasks/cukerail.rake
|
101
103
|
- spec/cukerail_spec.rb
|
102
104
|
- spec/spec_helper.rb
|
103
105
|
homepage: ''
|