dromedary 0.1.00 → 0.3.01
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dromedary/tasks.rb +11 -0
- data/lib/dromedary_initializer.rb +66 -3
- data/lib/tasks/dromedary.rake +267 -0
- data/lib/testrail.rb +264 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fea21242953b1f423fb38f9d24aa1b444c540469
|
4
|
+
data.tar.gz: 868bab3b50c29e45f3dac3a96dab2b60cde378b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dedb64bf51d47651dd8331f394a2ac02fce2aeea987a59869d40a58212cb1752e06b1d0d3b56269d996a10338001c44e2a2954c77ad2de4a68a5a729fd7f31a1
|
7
|
+
data.tar.gz: 21d7bef695d7c24b972cf3d1da30eda87a82fc3c6263dd3f5d580eaf0f61b42c6a0a5ee0e5c4b7a39f73aa406cef919fdd2d5efe7054935d45e93ae87a8189ac
|
@@ -1,15 +1,23 @@
|
|
1
1
|
module DromedaryInitializer
|
2
2
|
def self.run
|
3
|
-
if
|
3
|
+
if cucumber_not_initialized?
|
4
4
|
report_no_cucumber_found
|
5
5
|
elsif already_initialized?
|
6
6
|
report_already_initialized
|
7
7
|
else
|
8
|
+
create_directory 'config'
|
8
9
|
create_file 'config/dromedary.yml'
|
9
10
|
create_file 'features/support/dromedary_hooks.rb'
|
11
|
+
create_file 'config/cucumber.yml'
|
12
|
+
create_file 'Rakefile'
|
10
13
|
|
11
14
|
update_file 'config/dromedary.yml', dromedary_config_content
|
12
15
|
update_file 'features/support/dromedary_hooks.rb', dromedary_hooks_content
|
16
|
+
|
17
|
+
update_file 'config/cucumber.yml', cucumber_config_content
|
18
|
+
update_file '.gitignore', gitignore_content
|
19
|
+
update_file 'Rakefile', rakefile_content
|
20
|
+
update_file 'Gemfile', gemfile_content
|
13
21
|
end
|
14
22
|
end
|
15
23
|
|
@@ -44,7 +52,7 @@ module DromedaryInitializer
|
|
44
52
|
report_updating(file_name)
|
45
53
|
end
|
46
54
|
|
47
|
-
def self.
|
55
|
+
def self.cucumber_not_initialized?
|
48
56
|
!File.exist?('features/support/env.rb')
|
49
57
|
end
|
50
58
|
|
@@ -156,10 +164,65 @@ module DromedaryInitializer
|
|
156
164
|
'',
|
157
165
|
' # setting TestRail to generate reports at specific folder',
|
158
166
|
" unless @local == 'true'",
|
159
|
-
' File.open("artifacts/
|
167
|
+
' File.open("artifacts/testrail_reports/file_#{Time.now.to_i}.json}.json", "w") do |file|',
|
160
168
|
' file.puts @results.to_json',
|
161
169
|
' end',
|
162
170
|
' end',
|
163
171
|
'end']
|
164
172
|
end
|
173
|
+
|
174
|
+
def self.cucumber_config_content
|
175
|
+
['',
|
176
|
+
'# Following lines were generated by Dromedary gem',
|
177
|
+
'# It contains required Cucumber profiles to ensure that all reporting works',
|
178
|
+
'',
|
179
|
+
cucumber_config_structure]
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.cucumber_config_structure
|
183
|
+
['junit_report: --format pretty --format junit --out artifacts/junit_xml_reports',
|
184
|
+
'run_json_report: --format json --out artifacts/cucumber_json_reports/run.json',
|
185
|
+
'rerun_json_report: --format json --out artifacts/cucumber_json_reports/rerun.json',
|
186
|
+
'rerun_formatter: --format rerun --out artifacts/final_test_reports/fails.log']
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.gitignore_content
|
190
|
+
['',
|
191
|
+
gitignore_structure]
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.gitignore_structure
|
195
|
+
['artifacts/']
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.rakefile_content
|
199
|
+
['',
|
200
|
+
'',
|
201
|
+
'# require Dromedary gem dependencies',
|
202
|
+
rakefile_structure]
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.rakefile_structure
|
206
|
+
["require 'dromedary/tasks'",
|
207
|
+
'',
|
208
|
+
'# describing Dromedary rake tasks',
|
209
|
+
"desc 'Rake task to run all the Dromedary sequence'",
|
210
|
+
'task :run_dromedary, :run_on do |task, args|',
|
211
|
+
' ENV["RUN_ON"] = "#{args[:run_on]}"',
|
212
|
+
' %W[prepare_for_a_ride store_cases_titles run_cucumber merge_junit_reports get_case_ids[run] rerun_if_needed generate_cucumber_json_reports create_run[smoke,#{args[:run_on]}] close_run[#{args[:run_on]}] final_clean_ups].each do |task_name|',
|
213
|
+
' sh "rake #{task_name}" do',
|
214
|
+
' #ignore errors',
|
215
|
+
' end',
|
216
|
+
' end',
|
217
|
+
'end']
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.gemfile_content
|
221
|
+
['',
|
222
|
+
gemfile_structure]
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.gemfile_structure
|
226
|
+
["gem 'junit_merge'"]
|
227
|
+
end
|
165
228
|
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'yaml'
|
3
|
+
require_relative '../testrail'
|
4
|
+
|
5
|
+
DROMEDARY = YAML.load_file("#{Dir.pwd}/config/dromedary.yml")
|
6
|
+
|
7
|
+
# TASKS
|
8
|
+
|
9
|
+
# Preparation tasks
|
10
|
+
|
11
|
+
desc 'This task creates required folders and files'
|
12
|
+
task :prepare_for_a_ride do
|
13
|
+
%W[create_folders create_files].each do |task_name|
|
14
|
+
sh "rake #{task_name}" do
|
15
|
+
#ignore errors
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'This task creates required folder tree for reporting'
|
21
|
+
task :create_folders do
|
22
|
+
%W[artifacts artifacts/cucumber_json_reports artifacts/junit_xml_reports artifacts/testrail_reports artifacts/final_test_reports].each do |dir_name|
|
23
|
+
Dir.mkdir "#{dir_name}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'This task creates and updates required files for reporting'
|
28
|
+
task :create_files do
|
29
|
+
%W[artifacts/cucumber_json_reports/run.json artifacts/cucumber_json_reports/rerun.json artifacts/final_test_reports/final_cucumber_json_report.json artifacts/final_test_reports/run_results_with_case_id.json artifacts/final_test_reports/rerun_results_with_case_id.json artifacts/final_test_reports/test_cases.json].each do |file_name|
|
30
|
+
File.open(file_name, 'w') do |file|
|
31
|
+
file.puts '[]'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
File.open('artifacts/final_test_reports/final_junit_report.xml', 'w') do |file|
|
35
|
+
xml_structure.each do |line|
|
36
|
+
file.puts line
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Saving Test cases from remote TestRail project'
|
42
|
+
task :store_cases_titles do
|
43
|
+
@client = TestRail::APIClient.new(DROMEDARY['testrail']['url'])
|
44
|
+
@client.user = DROMEDARY['testrail']['user']
|
45
|
+
@client.password = DROMEDARY['testrail']['password']
|
46
|
+
|
47
|
+
project_id = DROMEDARY['testrail']['project_id']
|
48
|
+
suite_id = DROMEDARY['testrail']['suite_id']
|
49
|
+
cases = @client.get_cases_for_suite(project_id, suite_id)
|
50
|
+
@full_cases = @client.get_cases_titles(cases, project_id, suite_id)
|
51
|
+
|
52
|
+
File.open('artifacts/final_test_reports/test_cases.json', 'w') do |file|
|
53
|
+
require 'json'
|
54
|
+
file.puts @full_cases.to_json
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Runner tasks
|
59
|
+
|
60
|
+
desc 'Run Cucumber features for the first run'
|
61
|
+
task :run_cucumber do
|
62
|
+
sh "cucumber -p junit_report -p rerun_formatter -p run_json_report" do
|
63
|
+
#ignore errors
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
desc 'Rerun Cucumber features according to the fails.log'
|
68
|
+
task :rerun_failed do
|
69
|
+
sh "cucumber @artifacts/final_test_reports/fails.log -p junit_report -p rerun_json_report" do
|
70
|
+
#ignore errors
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
task :rerun_if_needed do
|
75
|
+
if File.file?("artifacts/final_test_reports/fails.log")
|
76
|
+
if File.read("artifacts/final_test_reports/fails.log").empty?
|
77
|
+
puts 'Rerun step skipped, no fails occurred during the first run'
|
78
|
+
else
|
79
|
+
fails = File.read("artifacts/final_test_reports/fails.log")
|
80
|
+
|
81
|
+
File.open('artifacts/final_test_reports/fails.log', 'w') do |file|
|
82
|
+
file.puts fails.gsub('\n', ' ')
|
83
|
+
end
|
84
|
+
|
85
|
+
sh "rake rerun_and_update_reports" do
|
86
|
+
#ignore errors
|
87
|
+
end
|
88
|
+
end
|
89
|
+
else
|
90
|
+
puts 'Rerun step skipped, no fails occurred during the first run'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
desc 'Rerun failed Cucumber features and update respective reports'
|
95
|
+
task :rerun_and_update_reports do
|
96
|
+
%W[clean_interim_reports rerun_failed merge_junit_reports get_case_ids[rerun]].each do |task_name|
|
97
|
+
sh "rake #{task_name}" do
|
98
|
+
#ignore errors
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Cleaning tasks
|
104
|
+
|
105
|
+
desc 'Cleaning all interim reports'
|
106
|
+
task :clean_interim_reports do
|
107
|
+
%W[clean_test_rail clean_junit].each do |task_name|
|
108
|
+
sh "rake #{task_name}" do
|
109
|
+
#ignore errors
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
desc 'Cleaning interim TestRail reports'
|
115
|
+
task :clean_test_rail do
|
116
|
+
catalog = 'artifacts/testrail_reports'
|
117
|
+
files = Dir.entries(catalog).delete_if { |entry| File.directory?(entry) }
|
118
|
+
files.map! { |f| "#{catalog}/#{f}" }
|
119
|
+
rm files
|
120
|
+
end
|
121
|
+
|
122
|
+
desc 'Cleaning interim JUnit reports'
|
123
|
+
task :clean_junit do
|
124
|
+
catalog = 'artifacts/junit_xml_reports'
|
125
|
+
files = Dir.entries(catalog).delete_if { |entry| File.directory?(entry) }
|
126
|
+
files.map! { |f| "#{catalog}/#{f}" }
|
127
|
+
rm files
|
128
|
+
end
|
129
|
+
|
130
|
+
desc 'Cleaning interim Cucumber JSON reports'
|
131
|
+
task :clean_cucumber_json do
|
132
|
+
catalog = 'artifacts/cucumber_json_reports'
|
133
|
+
files = Dir.entries(catalog).delete_if { |entry| File.directory?(entry) }
|
134
|
+
files.map! { |f| "#{catalog}/#{f}" }
|
135
|
+
rm files
|
136
|
+
end
|
137
|
+
|
138
|
+
desc 'Cleaning rudimentary folders'
|
139
|
+
task :clean_folders do
|
140
|
+
catalog = 'artifacts'
|
141
|
+
dirs = Dir.entries(catalog).drop 2
|
142
|
+
dirs.delete('final_test_reports')
|
143
|
+
dirs.map! { |f| "#{catalog}/#{f}" }
|
144
|
+
dirs.each do |dir_path|
|
145
|
+
remove_dir dir_path
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
desc 'Cleaning project tree from unnecessary files and folders'
|
150
|
+
task :final_clean_ups do
|
151
|
+
%W[clean_test_rail clean_junit clean_cucumber_json clean_folders].each do |task_name|
|
152
|
+
sh "rake #{task_name}" do
|
153
|
+
#ignore errors
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Report generation tasks
|
159
|
+
|
160
|
+
desc 'Merging interim JUnit reports to final JUnit report'
|
161
|
+
task :merge_junit_reports do
|
162
|
+
file_names = Dir.entries('artifacts/junit_xml_reports').delete_if { |entry| File.directory?(entry) }
|
163
|
+
file_names.each do |file_name|
|
164
|
+
sh "junit_merge artifacts/junit_xml_reports/#{file_name} artifacts/final_test_reports/final_junit_report.xml" do
|
165
|
+
#ignore errors
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
desc 'Merging interim Cucumber json reports to final Cucumber json report'
|
171
|
+
task :generate_cucumber_json_reports do
|
172
|
+
test_results = []
|
173
|
+
|
174
|
+
run_results = JSON.parse(File.read('artifacts/cucumber_json_reports/run.json'))
|
175
|
+
rerun_results = JSON.parse(File.read('artifacts/cucumber_json_reports/rerun.json'))
|
176
|
+
|
177
|
+
run_results.each do |x|
|
178
|
+
rerun_results.each do |y|
|
179
|
+
if y.values[0] == x.values[0]
|
180
|
+
x.merge!(y)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
test_results.push(x)
|
184
|
+
end
|
185
|
+
|
186
|
+
File.open('artifacts/final_test_reports/final_cucumber_json_report.json', 'w') do |file|
|
187
|
+
require 'json'
|
188
|
+
file.puts test_results.to_json
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
desc 'Generating interim TestRail report for a particular run'
|
193
|
+
task :get_case_ids, :run_type do |task, args|
|
194
|
+
@test_results = {}
|
195
|
+
file = File.read('artifacts/final_test_reports/test_cases.json')
|
196
|
+
@full_cases = JSON.parse(file)
|
197
|
+
|
198
|
+
file_names = Dir.entries('artifacts/testrail_reports').delete_if { |entry| File.directory?(entry) }
|
199
|
+
file_names.each do |file_name|
|
200
|
+
result = JSON.parse(File.read("artifacts/testrail_reports/#{file_name}"))
|
201
|
+
@test_results.update(result)
|
202
|
+
end
|
203
|
+
|
204
|
+
@results_json = []
|
205
|
+
@test_results.map do |full_desc,status_id|
|
206
|
+
n = 0
|
207
|
+
until n == status_id.count do
|
208
|
+
current_result = {:case_id => find_id(full_desc)[n], :status_id => status_id[n] } if find_id(full_desc)
|
209
|
+
@results_json.push(current_result)
|
210
|
+
n += 1
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
@results_json.compact!
|
215
|
+
File.open("artifacts/final_test_reports/#{args[:run_type]}_results_with_case_id.json", 'w') do |file|
|
216
|
+
file.write(@results_json.to_json)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
desc 'Creating Test Run on remote TestRail project'
|
221
|
+
task :create_run, :suite_type, :environment, :section_name do |task, args|
|
222
|
+
@client = TestRail::APIClient.new(DROMEDARY['testrail']['url'])
|
223
|
+
@client.user = DROMEDARY['testrail']['user']
|
224
|
+
@client.password = DROMEDARY['testrail']['password']
|
225
|
+
project_id = DROMEDARY['testrail']['project_id']
|
226
|
+
suite_id = DROMEDARY['testrail']['suite_id']
|
227
|
+
|
228
|
+
test_run_name = DROMEDARY['testrail']['test_run_default_name'] + ' ' + args[:suite_type].capitalize + ' on ' + args[:environment].capitalize
|
229
|
+
test_run = @client.add_run(project_id, suite_id, test_run_name)
|
230
|
+
file = File.open('artifacts/final_test_reports/test_run_id.txt', File::CREAT|File::TRUNC|File::RDWR)
|
231
|
+
file.puts test_run['id']
|
232
|
+
file.close
|
233
|
+
end
|
234
|
+
|
235
|
+
desc 'Closing Test Run on remote TestRail project'
|
236
|
+
task :close_run, :environment do
|
237
|
+
@client = TestRail::APIClient.new(DROMEDARY['testrail']['url'])
|
238
|
+
@client.user = DROMEDARY['testrail']['user']
|
239
|
+
@client.password = DROMEDARY['testrail']['password']
|
240
|
+
|
241
|
+
run_results = JSON.parse(File.read('artifacts/final_test_reports/run_results_with_case_id.json'))
|
242
|
+
rerun_results = JSON.parse(File.read('artifacts/final_test_reports/rerun_results_with_case_id.json'))
|
243
|
+
test_results = run_results + rerun_results
|
244
|
+
|
245
|
+
run_id = File.new('artifacts/final_test_reports/test_run_id.txt').read.chomp
|
246
|
+
@client.add_results_for_cases(run_id, test_results)
|
247
|
+
@client.mark_untested_tests_failed(run_id)
|
248
|
+
@client.close_run(run_id, data = {})
|
249
|
+
end
|
250
|
+
|
251
|
+
# METHODS
|
252
|
+
|
253
|
+
def xml_structure
|
254
|
+
['<?xml version="1.0" encoding="UTF-8"?>',
|
255
|
+
'<testsuite name="" tests="" failures="" errors="" time="" timestamp="">',
|
256
|
+
' <!-- Randomized with seed 00000 -->',
|
257
|
+
' <properties/>',
|
258
|
+
'</testsuite>']
|
259
|
+
end
|
260
|
+
|
261
|
+
def find_id(full_title)
|
262
|
+
@ids_array = []
|
263
|
+
@full_cases.select {|c| c['title'] == full_title.gsub(' ', ' ')}.each do |e|
|
264
|
+
@ids_array << e['id']
|
265
|
+
end
|
266
|
+
@ids_array unless @ids_array.empty?
|
267
|
+
end
|
data/lib/testrail.rb
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
#
|
2
|
+
# TestRail API binding for Ruby (API v2, available since TestRail 3.0)
|
3
|
+
#
|
4
|
+
# Learn more:
|
5
|
+
#
|
6
|
+
# http://docs.gurock.com/testrail-api2/start
|
7
|
+
# http://docs.gurock.com/testrail-api2/accessing
|
8
|
+
#
|
9
|
+
# Copyright Gurock Software GmbH. See license.md for details.
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'net/http'
|
13
|
+
require 'net/https'
|
14
|
+
require 'uri'
|
15
|
+
require 'json'
|
16
|
+
|
17
|
+
module TestRail
|
18
|
+
class APIClient
|
19
|
+
@url = ''
|
20
|
+
@user = ''
|
21
|
+
@password = ''
|
22
|
+
|
23
|
+
attr_accessor :user
|
24
|
+
attr_accessor :password
|
25
|
+
|
26
|
+
def initialize(base_url)
|
27
|
+
if !base_url.match(/\/$/)
|
28
|
+
base_url += '/'
|
29
|
+
end
|
30
|
+
@url = base_url + 'index.php?/api/v2/'
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_run(project_id, suite_id, test_run_name, section_id=nil)
|
34
|
+
cases_ids = section_id ? get_all_cases(project_id, suite_id, section_id) : get_cases_for_suite(project_id, suite_id).map {|item| item['id']}
|
35
|
+
data = {'suite_id'=> suite_id, 'name' => test_run_name,'include_all'=>false, 'case_ids' => cases_ids }
|
36
|
+
send_post("add_run/#{project_id}", data)
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_all_cases(project_id, suite_id, section_id)
|
40
|
+
all_sections = get_all_inherited_sections(project_id, suite_id, section_id)
|
41
|
+
cases_ids = []
|
42
|
+
all_sections.uniq!
|
43
|
+
all_sections.each do |section|
|
44
|
+
cases_ids += get_cases_for_section(project_id, suite_id, section)
|
45
|
+
end
|
46
|
+
cases_ids
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_cases_for_suite(project_id, suite_id)
|
50
|
+
send_get("get_cases/#{project_id}&suite_id=#{suite_id}")
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_cases_for_section(project_id, suite_id, section_id)
|
54
|
+
send_get("get_cases/#{project_id}&suite_id=#{suite_id}§ion_id=#{section_id}").map {|item| item['id']}
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_all_inherited_sections(project_id, suite_id, section_id)
|
58
|
+
hash = sections_hash(project_id, suite_id)
|
59
|
+
to_preceed = hash['entries'].find{|el| el['id'] == section_id}
|
60
|
+
results = []
|
61
|
+
get_entries_array to_preceed, results
|
62
|
+
results.map { |el| el['id']}
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_cases_titles(cases, project_id, suite_id)
|
66
|
+
sections = get_sections(project_id, suite_id)
|
67
|
+
full_cases = []
|
68
|
+
cases.each do |c|
|
69
|
+
c['title'] = full_title(c, sections)
|
70
|
+
full_cases << c
|
71
|
+
end
|
72
|
+
|
73
|
+
full_cases
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_results_for_cases(run_id, test_rail_results)
|
77
|
+
data = {}
|
78
|
+
data[:results] = test_rail_results
|
79
|
+
send_post("add_results_for_cases/#{run_id}", data)
|
80
|
+
end
|
81
|
+
|
82
|
+
def full_title(case_hash, sections)
|
83
|
+
parent_section_id = case_hash['section_id']
|
84
|
+
results = []
|
85
|
+
section = sections.find do |sec|
|
86
|
+
sec['id'] == parent_section_id
|
87
|
+
end
|
88
|
+
|
89
|
+
get_full_sections_title_for(section, sections, results)
|
90
|
+
results.push(case_hash['title']).join(' ')
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_section(section_id)
|
94
|
+
send_get("get_section/#{section_id}")
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_full_sections_title_for(section, sections, results)
|
98
|
+
results.unshift(section['name'])
|
99
|
+
unless section['depth'] == 0
|
100
|
+
parent_section = parent_section(section, sections)
|
101
|
+
get_full_sections_title_for(parent_section, sections, results)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
def get_entries_array(node, results)
|
107
|
+
results << node
|
108
|
+
node['entries'].each do |entry|
|
109
|
+
results << entry
|
110
|
+
unless entry['entries'].empty?
|
111
|
+
get_entries_array(entry, results)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def parent_section(section, sections)
|
117
|
+
sections.find { |sec| sec['id'] == section['parent_id'] }
|
118
|
+
end
|
119
|
+
|
120
|
+
def build_hash(node, array)
|
121
|
+
nodes_to_proceed = array.select do |section|
|
122
|
+
section['parent_id'] == node['id']
|
123
|
+
end
|
124
|
+
|
125
|
+
nodes_to_proceed.each do |n|
|
126
|
+
node['entries'] << n
|
127
|
+
array.delete n
|
128
|
+
build_hash(n, array)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def sections_hash(project_id, suite_id)
|
134
|
+
all_sections = get_sections(project_id, suite_id)
|
135
|
+
all_sections.map! {|el| el['entries'] =[]; el}
|
136
|
+
main = all_sections.find {|el| el['depth'] == 0}
|
137
|
+
all_sections.delete(main)
|
138
|
+
build_hash(main, all_sections)
|
139
|
+
main
|
140
|
+
end
|
141
|
+
|
142
|
+
def get_section_id(project_id, suite_id, section_title)
|
143
|
+
all_sections = get_sections(project_id, suite_id)
|
144
|
+
all_sections.find{|section| section['name'] == section_title}['id']
|
145
|
+
end
|
146
|
+
|
147
|
+
def get_sections(project_id, suite_id)
|
148
|
+
send_get("get_sections/#{project_id}&suite_id=#{suite_id}")
|
149
|
+
end
|
150
|
+
|
151
|
+
def add_result_for_case(run_id, case_id, data)
|
152
|
+
send_post("add_result_for_case/#{run_id}/#{case_id}", data)
|
153
|
+
end
|
154
|
+
|
155
|
+
def close_run(run_id, data)
|
156
|
+
send_post("close_run/#{run_id}", data)
|
157
|
+
end
|
158
|
+
|
159
|
+
def mark_untested_tests_failed(run_id)
|
160
|
+
tests = get_untested_tests(run_id)
|
161
|
+
return if tests.empty?
|
162
|
+
tests_ids = tests.map {|t| t['id']}
|
163
|
+
mark_failed_tests_for_run(run_id, tests_ids)
|
164
|
+
end
|
165
|
+
|
166
|
+
def add_milestone(project_id, ms_name)
|
167
|
+
data = {"name"=> ms_name + Time.now.strftime("_%H/%M/%S_%d/%m/%Y")}
|
168
|
+
response = send_post("add_milestone/#{project_id}", data)
|
169
|
+
response['id']
|
170
|
+
end
|
171
|
+
|
172
|
+
def close_milestone(ms_id)
|
173
|
+
data = {'is_completed' => true}
|
174
|
+
send_post("update_milestone/#{ms_id}", data)
|
175
|
+
end
|
176
|
+
|
177
|
+
def mark_failed_tests_for_run(run_id, tests_ids)
|
178
|
+
data = {}
|
179
|
+
data['results'] = []
|
180
|
+
tests_ids.each do |id|
|
181
|
+
data['results'] << {'test_id'=>id, 'status_id'=>5}
|
182
|
+
end
|
183
|
+
send_post("add_results/#{run_id}", data)
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_untested_tests(run_id)
|
187
|
+
send_get("get_tests/#{run_id}&status_id=3")
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
#
|
192
|
+
# Send Get
|
193
|
+
#
|
194
|
+
# Issues a GET request (read) against the API and returns the result
|
195
|
+
# (as Ruby hash).
|
196
|
+
#
|
197
|
+
# Arguments:
|
198
|
+
#
|
199
|
+
# uri The API method to call including parameters
|
200
|
+
# (e.g. get_case/1)
|
201
|
+
#
|
202
|
+
def send_get(uri)
|
203
|
+
_send_request('GET', uri, nil)
|
204
|
+
end
|
205
|
+
|
206
|
+
#
|
207
|
+
# Send POST
|
208
|
+
#
|
209
|
+
# Issues a POST request (write) against the API and returns the result
|
210
|
+
# (as Ruby hash).
|
211
|
+
#
|
212
|
+
# Arguments:
|
213
|
+
#
|
214
|
+
# uri The API method to call including parameters
|
215
|
+
# (e.g. add_case/1)
|
216
|
+
# data The data to submit as part of the request (as
|
217
|
+
# Ruby hash, strings must be UTF-8 encoded)
|
218
|
+
#
|
219
|
+
def send_post(uri, data)
|
220
|
+
_send_request('POST', uri, data)
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
def _send_request(method, uri, data)
|
225
|
+
url = URI.parse(@url + uri)
|
226
|
+
if method == 'POST'
|
227
|
+
request = Net::HTTP::Post.new(url.path + '?' + url.query)
|
228
|
+
request.body = JSON.dump(data)
|
229
|
+
else
|
230
|
+
request = Net::HTTP::Get.new(url.path + '?' + url.query)
|
231
|
+
end
|
232
|
+
request.basic_auth(@user, @password)
|
233
|
+
request.add_field('Content-Type', 'application/json')
|
234
|
+
|
235
|
+
conn = Net::HTTP.new(url.host, url.port)
|
236
|
+
if url.scheme == 'https'
|
237
|
+
conn.use_ssl = true
|
238
|
+
conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
239
|
+
end
|
240
|
+
response = conn.request(request)
|
241
|
+
|
242
|
+
if response.body && !response.body.empty?
|
243
|
+
result = JSON.parse(response.body)
|
244
|
+
else
|
245
|
+
result = {}
|
246
|
+
end
|
247
|
+
|
248
|
+
if response.code != '200'
|
249
|
+
if result && result.key?('error')
|
250
|
+
error = '"' + result['error'] + '"'
|
251
|
+
else
|
252
|
+
error = 'No additional error message received'
|
253
|
+
end
|
254
|
+
raise APIError.new('TestRail API returned HTTP %s (%s)' %
|
255
|
+
[response.code, error])
|
256
|
+
end
|
257
|
+
|
258
|
+
result
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
class APIError < StandardError
|
263
|
+
end
|
264
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dromedary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.01
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denys Bazarnyi
|
@@ -20,8 +20,11 @@ extra_rdoc_files: []
|
|
20
20
|
files:
|
21
21
|
- bin/dromedary
|
22
22
|
- lib/dromedary.rb
|
23
|
+
- lib/dromedary/tasks.rb
|
23
24
|
- lib/dromedary_initializer.rb
|
24
|
-
|
25
|
+
- lib/tasks/dromedary.rake
|
26
|
+
- lib/testrail.rb
|
27
|
+
homepage: http://rubygems.org/gems/dromedary
|
25
28
|
licenses:
|
26
29
|
- MIT
|
27
30
|
metadata: {}
|