dromedary 0.1.00 → 0.3.01
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/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: {}
|