rspec_parallel 0.1.6 → 0.1.7
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.
- data/Gemfile.lock +3 -1
- data/lib/rspec_parallel/color_helper.rb +1 -1
- data/lib/rspec_parallel/report_helper.rb +289 -0
- data/lib/rspec_parallel/version.rb +1 -1
- data/lib/rspec_parallel.rb +29 -281
- data/rspec_parallel.gemspec +1 -0
- metadata +19 -2
data/Gemfile.lock
CHANGED
@@ -0,0 +1,289 @@
|
|
1
|
+
# generate or update report
|
2
|
+
module RParallel
|
3
|
+
module ReportHelper
|
4
|
+
|
5
|
+
def get_report_folder(base_folder, get_next = false)
|
6
|
+
i = 0
|
7
|
+
|
8
|
+
folders = Dir.glob("#{base_folder}/rerun*").sort
|
9
|
+
unless folders.nil? || folders == []
|
10
|
+
i = folders.last.split("rerun",2).last.to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
if get_next
|
14
|
+
i = i + 1
|
15
|
+
end
|
16
|
+
|
17
|
+
return base_folder if i == 0
|
18
|
+
|
19
|
+
File.join(base_folder, "rerun#{i.to_s}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_last_report_file(base_folder, single_report)
|
23
|
+
if single_report
|
24
|
+
return File.join(base_folder, "junitResult.xml")
|
25
|
+
else
|
26
|
+
report_folder = get_report_folder(base_folder, false)
|
27
|
+
return File.join(report_folder, "junitResult.xml")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_failed_cases(base_folder, single_report)
|
32
|
+
queue = Queue.new
|
33
|
+
|
34
|
+
last_report_file = get_last_report_file(base_folder, single_report)
|
35
|
+
unless File.exists? last_report_file
|
36
|
+
puts yellow("can't find result of last run")
|
37
|
+
exit(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
doc = Nokogiri::XML(open(last_report_file))
|
42
|
+
doc.xpath("//result/suites/suite/cases/case").each do |c|
|
43
|
+
unless c.xpath(".//errorDetails").empty?
|
44
|
+
rerun_cmd = c.xpath(".//rerunCommand").text
|
45
|
+
line = rerun_cmd.split('#')[0].gsub('rspec ', '').strip
|
46
|
+
queue << line
|
47
|
+
end
|
48
|
+
end
|
49
|
+
rescue
|
50
|
+
puts red("invalid format of report xml")
|
51
|
+
exit(1)
|
52
|
+
end
|
53
|
+
|
54
|
+
queue
|
55
|
+
end
|
56
|
+
|
57
|
+
def generate_reports(report_folder, time, case_info_list, options)
|
58
|
+
%x[mkdir #{report_folder}] unless File.exists? report_folder
|
59
|
+
report_file_path = File.join(report_folder, 'junitResult.xml')
|
60
|
+
|
61
|
+
if options[:longevity] > 1 && options[:single_report]
|
62
|
+
summary_doc = Nokogiri::XML(open(report_file_path, 'r')) do |config|
|
63
|
+
config.default_xml.noblanks
|
64
|
+
end
|
65
|
+
summary_doc.search("//result/duration").remove
|
66
|
+
summary_doc.search("//result/keepLongStdio").remove
|
67
|
+
else
|
68
|
+
builder = Nokogiri::XML::Builder.new("encoding" => 'UTF-8') do |xml|
|
69
|
+
xml.result {
|
70
|
+
xml.suites
|
71
|
+
}
|
72
|
+
end
|
73
|
+
summary_doc = builder.doc
|
74
|
+
end
|
75
|
+
|
76
|
+
# reorder the tests by class_name
|
77
|
+
class_name_list = []
|
78
|
+
case_info_list.each do |case_info|
|
79
|
+
class_name = case_info['class_name']
|
80
|
+
class_name_list << class_name
|
81
|
+
end
|
82
|
+
class_name_list.uniq!
|
83
|
+
class_name_list.sort!
|
84
|
+
class_name_list.each do |class_name|
|
85
|
+
temp_case_info_list = []
|
86
|
+
case_info_list.each do |case_info|
|
87
|
+
if case_info['class_name'] == class_name
|
88
|
+
temp_case_info_list << case_info
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
generate_single_file_report(report_folder, temp_case_info_list, options, summary_doc.at("//result/suites"))
|
93
|
+
end
|
94
|
+
|
95
|
+
if options[:rerun] && options[:single_report]
|
96
|
+
last_report_file = get_last_report_file(options[:report_folder], options[:single_report])
|
97
|
+
last_doc = Nokogiri::XML(open(last_report_file))
|
98
|
+
doc = update_single_report(last_doc, case_info_list)
|
99
|
+
fr = File.new(report_file_path, 'w')
|
100
|
+
fr.puts doc.to_xml(:indent => 2)
|
101
|
+
fr.close
|
102
|
+
return
|
103
|
+
end
|
104
|
+
|
105
|
+
Nokogiri::XML::Builder.with(summary_doc.at("//result")) do |xml|
|
106
|
+
xml.duration time
|
107
|
+
xml.keepLongStdio "false"
|
108
|
+
end
|
109
|
+
|
110
|
+
fr = File.new(report_file_path, 'w')
|
111
|
+
fr.puts summary_doc.to_xml(:indent => 2)
|
112
|
+
fr.close
|
113
|
+
end
|
114
|
+
|
115
|
+
def update_single_report(doc, case_info_list)
|
116
|
+
doc.xpath("//result/suites/suite/cases/case").each do |c1|
|
117
|
+
unless c1.xpath(".//errorDetails").empty?
|
118
|
+
test_name = c1.at_xpath(".//testName").text
|
119
|
+
case_info_list.each do |c2|
|
120
|
+
if test_name == c2['test_name'] #.encode({:xml => :attr})
|
121
|
+
c1.at_xpath(".//duration").content = c2['duration']
|
122
|
+
if c2['status'] == 'fail'
|
123
|
+
text = c2['error_message'].gsub('Failure/Error: ', '') + "\n"
|
124
|
+
text += c2['error_stack_trace'].gsub('# ', '')
|
125
|
+
c1.at_xpath(".//errorStackTrace").content = text.strip
|
126
|
+
c1.at_xpath(".//errorDetails").content = c2['error_details']
|
127
|
+
c1.at_xpath(".//rerunCommand").content = c2['rerun_cmd'].strip
|
128
|
+
else
|
129
|
+
c1.search(".//errorDetails").remove
|
130
|
+
c1.search(".//errorStackTrace").remove
|
131
|
+
c1.search(".//rerunCommand").remove
|
132
|
+
end
|
133
|
+
break
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
doc
|
139
|
+
end
|
140
|
+
|
141
|
+
def generate_single_file_report(report_folder, case_info_list, options, suites_doc)
|
142
|
+
return if case_info_list == []
|
143
|
+
class_name = case_info_list[0]['class_name']
|
144
|
+
file_name = File.join(report_folder, class_name.gsub(/:+/, '-') + '.xml')
|
145
|
+
|
146
|
+
suite_duration = 0.0
|
147
|
+
fail_num = 0
|
148
|
+
error_num = 0
|
149
|
+
pending_num = 0
|
150
|
+
stdout = ''
|
151
|
+
stderr = ''
|
152
|
+
stdout_list = []
|
153
|
+
stderr_list = []
|
154
|
+
case_desc_list = []
|
155
|
+
case_info_list.each do |case_info|
|
156
|
+
suite_duration += case_info['duration']
|
157
|
+
stdout_list << case_info['stdout']
|
158
|
+
stderr_list << case_info['stderr']
|
159
|
+
case_desc_list << case_info['test_desc']
|
160
|
+
if case_info['status'] == 'fail'
|
161
|
+
if case_info['error_message'].include? "expect"
|
162
|
+
fail_num += 1
|
163
|
+
else
|
164
|
+
error_num += 1
|
165
|
+
end
|
166
|
+
elsif case_info['status'] == 'pending'
|
167
|
+
pending_num += 1
|
168
|
+
end
|
169
|
+
end
|
170
|
+
stdout_list.uniq!
|
171
|
+
stderr_list.uniq!
|
172
|
+
case_desc_list.sort!
|
173
|
+
stdout_list.each {|s| stdout += s}
|
174
|
+
stderr_list.each {|s| stderr += s}
|
175
|
+
|
176
|
+
suite_builder = Nokogiri::XML::Builder.with(suites_doc) do |xml|
|
177
|
+
xml.suite {
|
178
|
+
xml.file file_name
|
179
|
+
xml.name class_name.gsub(':', '_')
|
180
|
+
if stdout.length > 0
|
181
|
+
xml.stdout stdout
|
182
|
+
else
|
183
|
+
xml.stdout ""
|
184
|
+
end
|
185
|
+
if stderr.length > 0
|
186
|
+
xml.stderr stderr
|
187
|
+
else
|
188
|
+
xml.stderr ""
|
189
|
+
end
|
190
|
+
xml.duration suite_duration
|
191
|
+
xml.cases
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
longevity_report = options[:longevity] > 1 && options[:single_report]
|
196
|
+
if longevity_report
|
197
|
+
single_report = Nokogiri::XML(open(file_name)) do |config|
|
198
|
+
config.default_xml.noblanks
|
199
|
+
end
|
200
|
+
# delete 'system-out' and 'system-err', using the new one
|
201
|
+
single_report.search("//system-out").remove
|
202
|
+
single_report.search("//system-err").remove
|
203
|
+
else
|
204
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
205
|
+
xml.testsuite(:name => class_name,
|
206
|
+
:tests => case_info_list.size,
|
207
|
+
:time => suite_duration,
|
208
|
+
:failures=> fail_num,
|
209
|
+
:errors => error_num,
|
210
|
+
:skipped => pending_num)
|
211
|
+
end
|
212
|
+
single_report = builder.doc
|
213
|
+
end
|
214
|
+
|
215
|
+
case_desc_list.each do |case_desc|
|
216
|
+
i = case_info_list.index { |c| c['test_desc'] == case_desc }
|
217
|
+
case_info = case_info_list[i]
|
218
|
+
if options[:longevity] == 0
|
219
|
+
test_name = case_info['test_name']
|
220
|
+
else
|
221
|
+
test_name = "#{options[:longevity]}-"+case_info['test_name']
|
222
|
+
end
|
223
|
+
test_name += " (PENDING)" if case_info['status'] == 'pending'
|
224
|
+
# test_name = test_name.encode({:xml => :attr})
|
225
|
+
if case_info['status'] == 'fail'
|
226
|
+
if case_info['error_message'].include? "expected"
|
227
|
+
type = "RSpec::Expectations::ExpectationNotMetError"
|
228
|
+
elsif case_info['error_message'].include? "RuntimeError"
|
229
|
+
type = "RuntimeError"
|
230
|
+
else
|
231
|
+
type = "UnknownError"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# add new case into suite report for summary report
|
236
|
+
Nokogiri::XML::Builder.with(suite_builder.doc.at("//cases")) do |xml|
|
237
|
+
xml.case {
|
238
|
+
xml.duration case_info['duration']
|
239
|
+
xml.className class_name
|
240
|
+
xml.testName test_name
|
241
|
+
xml.skipped case_info['status'] == 'pending'
|
242
|
+
if case_info['status'] == 'fail'
|
243
|
+
xml.errorStackTrace {
|
244
|
+
xml.text case_info['error_message'].gsub('Failure/Error: ', '')
|
245
|
+
xml.text case_info['error_stack_trace'].gsub('# ', '').strip
|
246
|
+
}
|
247
|
+
xml.errorDetails case_info['error_details']
|
248
|
+
xml.rerunCommand case_info['rerun_cmd'].strip
|
249
|
+
end
|
250
|
+
xml.failedSince '0'
|
251
|
+
}
|
252
|
+
end
|
253
|
+
|
254
|
+
# add new case into single report
|
255
|
+
Nokogiri::XML::Builder.with(single_report.at("testsuite")) do |xml|
|
256
|
+
xml.testcase(:name => test_name, :time => case_info['duration']) {
|
257
|
+
if case_info['status'] == 'pending'
|
258
|
+
xml.skipped
|
259
|
+
elsif case_info['status'] == 'fail'
|
260
|
+
xml.failure(:type => type, :message => case_info['error_details']) {
|
261
|
+
xml.text case_info['error_message'].gsub('Failure/Error: ', '')
|
262
|
+
xml.text case_info['error_stack_trace'].gsub('# ', '').strip
|
263
|
+
}
|
264
|
+
xml.rerunCommand case_info['rerun_cmd'].strip
|
265
|
+
end
|
266
|
+
}
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
Nokogiri::XML::Builder.with(single_report.at("testsuite")) do |xml|
|
271
|
+
if stdout.length > 0
|
272
|
+
xml.send(:'system-out', stdout)
|
273
|
+
else
|
274
|
+
xml.send(:'system-out', "")
|
275
|
+
end
|
276
|
+
if stderr.length > 0
|
277
|
+
xml.send(:'system-err', stderr)
|
278
|
+
else
|
279
|
+
xml.send(:'system-err', "")
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
ff = File.new(file_name, 'w')
|
284
|
+
ff.puts single_report.to_xml(:indent => 2)
|
285
|
+
ff.close
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
end
|
data/lib/rspec_parallel.rb
CHANGED
@@ -3,13 +3,14 @@ $LOAD_PATH << File.dirname(__FILE__)
|
|
3
3
|
require 'progressbar'
|
4
4
|
require 'thread'
|
5
5
|
require 'find'
|
6
|
-
require '
|
7
|
-
include REXML
|
6
|
+
require 'nokogiri'
|
8
7
|
|
9
8
|
require 'rspec_parallel/color_helper'
|
10
9
|
require 'rspec_parallel/version'
|
10
|
+
require 'rspec_parallel/report_helper'
|
11
11
|
include RParallel
|
12
|
-
include RParallel::
|
12
|
+
include RParallel::ColorHelper
|
13
|
+
include RParallel::ReportHelper
|
13
14
|
|
14
15
|
class RspecParallel
|
15
16
|
|
@@ -20,23 +21,21 @@ class RspecParallel
|
|
20
21
|
attr_reader :interrupted
|
21
22
|
|
22
23
|
attr_accessor :thread_number
|
23
|
-
attr_accessor :max_rerun_times
|
24
24
|
attr_accessor :max_thread_number
|
25
25
|
|
26
26
|
def initialize(options = {})
|
27
27
|
@options = {:thread_number => 4, :case_folder => "./spec/", :report_folder => "./reports/",
|
28
28
|
:filter => {}, :env_list => [], :show_pending => false, :rerun => false,
|
29
|
-
:single_report => false, :
|
30
|
-
:
|
29
|
+
:single_report => false, :random_order => false, :random_seed => nil,
|
30
|
+
:max_thread_number => 16, :longevity => 0}.merge(options)
|
31
31
|
@thread_number = @options[:thread_number]
|
32
|
-
@max_rerun_times = @options[:max_rerun_times]
|
33
32
|
@max_thread_number = @options[:max_thread_number]
|
34
33
|
|
35
|
-
@longevity = @options[:longevity_time]
|
36
34
|
@case_number = 0
|
37
35
|
@failure_number = 0
|
38
36
|
@pending_number = 0
|
39
37
|
@interrupted = false
|
38
|
+
@target = @options[:target]
|
40
39
|
end
|
41
40
|
|
42
41
|
def run_tests()
|
@@ -61,21 +60,14 @@ class RspecParallel
|
|
61
60
|
single_report = @options[:single_report]
|
62
61
|
|
63
62
|
if !single_report && rerun
|
64
|
-
@report_folder =
|
63
|
+
@report_folder = get_report_folder(@options[:report_folder], true)
|
65
64
|
end
|
66
65
|
|
67
66
|
@report_folder = @options[:report_folder] if @report_folder.nil?
|
68
67
|
|
69
|
-
if @report_folder.include? "rerun#{@max_rerun_times + 1}"
|
70
|
-
@return_message = "rerun task has been executed for #{@max_rerun_times}" +
|
71
|
-
" times, maybe you should start a new run"
|
72
|
-
puts yellow(@return_message)
|
73
|
-
return @return_message
|
74
|
-
end
|
75
|
-
|
76
68
|
filter = @options[:filter]
|
77
69
|
if rerun
|
78
|
-
get_failed_cases
|
70
|
+
@queue = get_failed_cases(@options[:report_folder], single_report)
|
79
71
|
else
|
80
72
|
parse_case_list(filter)
|
81
73
|
end
|
@@ -185,8 +177,8 @@ class RspecParallel
|
|
185
177
|
end
|
186
178
|
end
|
187
179
|
|
188
|
-
#CI: true - update ; default: false - new file
|
189
|
-
generate_reports(end_time - start_time,
|
180
|
+
# CI: true - update ; default: false - new file
|
181
|
+
generate_reports(@report_folder, end_time - start_time, @case_info_list, @options)
|
190
182
|
|
191
183
|
@return_message
|
192
184
|
end
|
@@ -313,6 +305,8 @@ class RspecParallel
|
|
313
305
|
tags_filter_list = pattern_filter_list
|
314
306
|
end
|
315
307
|
|
308
|
+
tags_filter_list = random_tests(tags_filter_list) if @options[:random_order]
|
309
|
+
|
316
310
|
tags_filter_list = reorder_tests(tags_filter_list)
|
317
311
|
|
318
312
|
tags_filter_list.each { |t|
|
@@ -320,56 +314,6 @@ class RspecParallel
|
|
320
314
|
}
|
321
315
|
end
|
322
316
|
|
323
|
-
def get_single_folder(folder_prefix, get_next=false)
|
324
|
-
report_folder = @options[:report_folder]
|
325
|
-
i = 0
|
326
|
-
if folder_prefix == "rerun"
|
327
|
-
folders = Dir.glob("#{report_folder}/rerun*").sort
|
328
|
-
unless folders.nil? || folders == []
|
329
|
-
i = folders.last.split("rerun",2).last.to_i
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
if get_next
|
334
|
-
i = i+1
|
335
|
-
end
|
336
|
-
|
337
|
-
if i == 0
|
338
|
-
return report_folder
|
339
|
-
end
|
340
|
-
|
341
|
-
folder = File.join(report_folder, folder_prefix+"#{i.to_s}")
|
342
|
-
|
343
|
-
end
|
344
|
-
|
345
|
-
def get_failed_cases
|
346
|
-
if !@options[:single_report]
|
347
|
-
last_report_folder = get_single_folder("rerun", false)
|
348
|
-
last_report_file_path = File.join(last_report_folder, "junitResult.xml")
|
349
|
-
else
|
350
|
-
last_report_file_path = File.join(@report_folder, "junitResult.xml")
|
351
|
-
end
|
352
|
-
unless File.exists? last_report_file_path
|
353
|
-
puts yellow("can't find result of last run")
|
354
|
-
exit(1)
|
355
|
-
end
|
356
|
-
report_file = File.new(last_report_file_path)
|
357
|
-
begin
|
358
|
-
@doc = REXML::Document.new report_file
|
359
|
-
rescue
|
360
|
-
puts red("invalid format of report xml")
|
361
|
-
exit(1)
|
362
|
-
end
|
363
|
-
|
364
|
-
@doc.elements.each("result/suites/suite/cases/case") do |c|
|
365
|
-
if c.get_elements("errorDetails")[0]
|
366
|
-
rerun_cmd = c.get_elements("rerunCommand")[0].text
|
367
|
-
line = rerun_cmd.split('#')[0].gsub('rspec ', '').strip
|
368
|
-
@queue << line
|
369
|
-
end
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
317
|
def run_task(task, env_extras)
|
374
318
|
cmd = [] # Preparing command for popen
|
375
319
|
cmd << ENV.to_hash.merge(env_extras)
|
@@ -384,6 +328,22 @@ class RspecParallel
|
|
384
328
|
output
|
385
329
|
end
|
386
330
|
|
331
|
+
def random_tests(case_list)
|
332
|
+
if @options[:random_seed]
|
333
|
+
seed = @options[:random_seed].to_i
|
334
|
+
else
|
335
|
+
seed = Time.now.to_i
|
336
|
+
end
|
337
|
+
puts yellow("running tests randomly with the seed: #{seed}")
|
338
|
+
rand_num = Random.new(seed)
|
339
|
+
|
340
|
+
random_case_list = []
|
341
|
+
case_list.sort_by { rand_num.rand }.each do |c|
|
342
|
+
random_case_list << c
|
343
|
+
end
|
344
|
+
random_case_list
|
345
|
+
end
|
346
|
+
|
387
347
|
def reorder_tests(case_list)
|
388
348
|
return case_list
|
389
349
|
end
|
@@ -485,216 +445,4 @@ class RspecParallel
|
|
485
445
|
result
|
486
446
|
end
|
487
447
|
|
488
|
-
def generate_reports(time, update_report)
|
489
|
-
%x[mkdir #{@report_folder}] unless File.exists? @report_folder
|
490
|
-
@summary_report = ""
|
491
|
-
|
492
|
-
class_name_list = []
|
493
|
-
@case_info_list.each do |case_info|
|
494
|
-
class_name = case_info['class_name']
|
495
|
-
class_name_list << class_name
|
496
|
-
end
|
497
|
-
class_name_list.uniq!
|
498
|
-
class_name_list.sort!
|
499
|
-
class_name_list.each do |class_name|
|
500
|
-
temp_case_info_list = []
|
501
|
-
@case_info_list.each do |case_info|
|
502
|
-
if case_info['class_name'] == class_name
|
503
|
-
temp_case_info_list << case_info
|
504
|
-
end
|
505
|
-
end
|
506
|
-
#CI: should insert into file while single_report == true
|
507
|
-
generate_single_file_report(temp_case_info_list, @longevity > 1 && @options[:single_report])
|
508
|
-
end
|
509
|
-
|
510
|
-
if update_report
|
511
|
-
update_ci_report
|
512
|
-
end
|
513
|
-
|
514
|
-
summary_end = "</suites>\n"
|
515
|
-
summary_end += "<duration>#{time}</duration>\n"
|
516
|
-
summary_end += "<keepLongStdio>false</keepLongStdio>\n"
|
517
|
-
summary_end += "</result>\n"
|
518
|
-
|
519
|
-
|
520
|
-
report_file_path = File.join(@report_folder, 'junitResult.xml')
|
521
|
-
|
522
|
-
|
523
|
-
if @longevity > 1 && @options[:single_report]
|
524
|
-
temp_file = File.open(report_file_path, 'r')
|
525
|
-
content = temp_file.read
|
526
|
-
report = content.split("</suites>",2).first
|
527
|
-
report += @summary_report
|
528
|
-
temp_file.close
|
529
|
-
fr = File.new(report_file_path, 'w')
|
530
|
-
fr.puts report
|
531
|
-
fr.puts summary_end
|
532
|
-
elsif update_report
|
533
|
-
fr = File.new(report_file_path, 'w')
|
534
|
-
fr.puts @doc
|
535
|
-
else
|
536
|
-
fr = File.new(report_file_path, 'w')
|
537
|
-
fr.puts "<?xml version='1.0' encoding='UTF-8'?>"
|
538
|
-
fr.puts "<result>"
|
539
|
-
fr.puts "<suites>"
|
540
|
-
fr.puts @summary_report
|
541
|
-
fr.puts summary_end
|
542
|
-
end
|
543
|
-
fr.close
|
544
|
-
|
545
|
-
end
|
546
|
-
|
547
|
-
def update_ci_report
|
548
|
-
@doc.elements.each("result/suites/suite/cases/case") do |c1|
|
549
|
-
if c1.get_elements("errorDetails")[0]
|
550
|
-
test_name = c1.get_elements("testName")[0].text
|
551
|
-
@case_info_list.each do |c2|
|
552
|
-
if test_name == c2['test_name'].encode({:xml => :attr})
|
553
|
-
c1.get_elements("duration")[0].text = c2['duration']
|
554
|
-
if c2['status'] == 'fail'
|
555
|
-
text = c2['error_message'].gsub('Failure/Error: ', '') + "\n"
|
556
|
-
text += c2['error_stack_trace'].gsub('# ', '')
|
557
|
-
c1.get_elements("errorStackTrace")[0].text = text
|
558
|
-
c1.get_elements("errorDetails")[0].text = c2['error_details']
|
559
|
-
c1.get_elements("rerunCommand")[0].text = c2['rerun_cmd']
|
560
|
-
else
|
561
|
-
c1.delete c1.get_elements("errorDetails")[0]
|
562
|
-
c1.delete c1.get_elements("errorStackTrace")[0]
|
563
|
-
c1.delete c1.get_elements("rerunCommand")[0]
|
564
|
-
end
|
565
|
-
break
|
566
|
-
end
|
567
|
-
end
|
568
|
-
end
|
569
|
-
end
|
570
|
-
end
|
571
|
-
|
572
|
-
def generate_single_file_report(case_info_list, is_update)
|
573
|
-
return if case_info_list == []
|
574
|
-
class_name = case_info_list[0]['class_name']
|
575
|
-
file_name = File.join(@report_folder, class_name.gsub(/:+/, '-') + '.xml')
|
576
|
-
name = class_name.gsub(':', '_')
|
577
|
-
|
578
|
-
suite_duration = 0.0
|
579
|
-
fail_num = 0
|
580
|
-
error_num = 0
|
581
|
-
pending_num = 0
|
582
|
-
stdout = ''
|
583
|
-
stderr = ''
|
584
|
-
stdout_list = []
|
585
|
-
stderr_list = []
|
586
|
-
case_desc_list = []
|
587
|
-
case_info_list.each do |case_info|
|
588
|
-
suite_duration += case_info['duration']
|
589
|
-
stdout_list << case_info['stdout']
|
590
|
-
stderr_list << case_info['stderr']
|
591
|
-
case_desc_list << case_info['test_desc']
|
592
|
-
if case_info['status'] == 'fail'
|
593
|
-
if case_info['error_message'].include? "expect"
|
594
|
-
fail_num += 1
|
595
|
-
else
|
596
|
-
error_num += 1
|
597
|
-
end
|
598
|
-
elsif case_info['status'] == 'pending'
|
599
|
-
pending_num += 1
|
600
|
-
end
|
601
|
-
end
|
602
|
-
stdout_list.uniq!
|
603
|
-
stderr_list.uniq!
|
604
|
-
case_desc_list.sort!
|
605
|
-
stdout_list.each {|s| stdout += s}
|
606
|
-
stderr_list.each {|s| stderr += s}
|
607
|
-
|
608
|
-
@summary_report += "<suite>\n"
|
609
|
-
@summary_report += "<file>#{file_name}</file>\n"
|
610
|
-
@summary_report += "<name>#{name}</name>\n"
|
611
|
-
@summary_report += "<stdout>\n"
|
612
|
-
@summary_report += stdout.encode({:xml => :text}) if stdout.length > 0
|
613
|
-
@summary_report += "</stdout>\n"
|
614
|
-
@summary_report += "<stderr>\n"
|
615
|
-
@summary_report += stderr.encode({:xml => :text}) if stderr.length > 0
|
616
|
-
@summary_report += "</stderr>\n"
|
617
|
-
@summary_report += "<duration>#{suite_duration}</duration>\n"
|
618
|
-
@summary_report += "<cases>\n"
|
619
|
-
|
620
|
-
single_output = ""
|
621
|
-
|
622
|
-
case_desc_list.each do |case_desc|
|
623
|
-
i = case_info_list.index {|c| c['test_desc'] == case_desc}
|
624
|
-
case_info = case_info_list[i]
|
625
|
-
if @longevity == 0
|
626
|
-
test_name = case_info['test_name']
|
627
|
-
else
|
628
|
-
test_name = "#{@longevity}-"+case_info['test_name']
|
629
|
-
end
|
630
|
-
test_name += " (PENDING)" if case_info['status'] == 'pending'
|
631
|
-
test_name = test_name.encode({:xml => :attr})
|
632
|
-
@summary_report += "<case>\n"
|
633
|
-
@summary_report += "<duration>#{case_info['duration']}</duration>\n"
|
634
|
-
@summary_report += "<className>#{class_name}</className>\n"
|
635
|
-
@summary_report += "<testName>#{test_name}</testName>\n"
|
636
|
-
@summary_report += "<skipped>#{case_info['status'] == 'pending'}</skipped>\n"
|
637
|
-
|
638
|
-
single_output += "<testcase name=#{test_name} time=\"#{case_info['duration']}\">\n"
|
639
|
-
single_output += "<skipped/>\n" if case_info['status'] == 'pending'
|
640
|
-
|
641
|
-
if case_info['status'] == 'fail'
|
642
|
-
@summary_report += "<errorStackTrace>\n"
|
643
|
-
@summary_report += case_info['error_message'].encode({:xml => :text}).gsub('Failure/Error: ', '')
|
644
|
-
@summary_report += case_info['error_stack_trace'].encode({:xml => :text}).gsub('# ', '')
|
645
|
-
@summary_report += "</errorStackTrace>\n"
|
646
|
-
@summary_report += "<errorDetails>\n"
|
647
|
-
@summary_report += case_info['error_details'].encode({:xml => :text})
|
648
|
-
@summary_report += "</errorDetails>\n"
|
649
|
-
@summary_report += "<rerunCommand>#{case_info['rerun_cmd'].encode({:xml => :text})}</rerunCommand>\n"
|
650
|
-
|
651
|
-
if case_info['error_message'].include? "expected"
|
652
|
-
type = "RSpec::Expectations::ExpectationNotMetError"
|
653
|
-
elsif case_info['error_message'].include? "RuntimeError"
|
654
|
-
type = "RuntimeError"
|
655
|
-
else
|
656
|
-
type = "UnknownError"
|
657
|
-
end
|
658
|
-
single_output += "<failure type=\"#{type}\" message=#{case_info['error_details'].encode({:xml => :attr})}>\n"
|
659
|
-
single_output += case_info['error_message'].encode({:xml => :text}).gsub('Failure/Error: ', '')
|
660
|
-
single_output += case_info['error_stack_trace'].encode({:xml => :text}).gsub('# ', '')
|
661
|
-
single_output += "</failure>\n"
|
662
|
-
single_output += "<rerunCommand>#{case_info['rerun_cmd'].encode({:xml => :text})}</rerunCommand>\n"
|
663
|
-
end
|
664
|
-
@summary_report += "<failedSince>0</failedSince>\n"
|
665
|
-
@summary_report += "</case>\n"
|
666
|
-
|
667
|
-
single_output += "</testcase>\n"
|
668
|
-
end
|
669
|
-
|
670
|
-
@summary_report += "</cases>\n"
|
671
|
-
@summary_report += "</suite>"
|
672
|
-
single_end = "<system-out>\n"
|
673
|
-
single_end += stdout.encode({:xml => :text}) if stdout.length > 0
|
674
|
-
single_end += "</system-out>\n"
|
675
|
-
single_end += "<system-err>\n"
|
676
|
-
single_end += stderr.encode({:xml => :text}) if stderr.length > 0
|
677
|
-
single_end += "</system-err>\n"
|
678
|
-
single_end += "</testsuite>\n"
|
679
|
-
|
680
|
-
|
681
|
-
if is_update == true
|
682
|
-
temp_file = File.open(file_name, 'r')
|
683
|
-
content = temp_file.read
|
684
|
-
content = content.split("<system-out>",2).first
|
685
|
-
content += single_output
|
686
|
-
temp_file.close
|
687
|
-
ff = File.new(file_name, 'w')
|
688
|
-
ff.puts content
|
689
|
-
ff.puts single_end
|
690
|
-
else
|
691
|
-
ff = File.new(file_name, 'w')
|
692
|
-
ff.puts '<?xml version="1.0" encoding="UTF-8"?>'
|
693
|
-
ff.puts "<testsuite name=\"#{class_name}\" tests=\"#{case_info_list.size}\" time=\"#{suite_duration}\" failures=\"#{fail_num}\" errors=\"#{error_num}\" skipped=\"#{pending_num}\">\n"
|
694
|
-
ff.puts single_output
|
695
|
-
ff.puts single_end
|
696
|
-
end
|
697
|
-
ff.close
|
698
|
-
|
699
|
-
end
|
700
448
|
end
|
data/rspec_parallel.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec_parallel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: progressbar
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 0.11.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: nokogiri
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.5.2
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.2
|
30
46
|
description: parallel all rspec examples
|
31
47
|
email: support@vmware.com
|
32
48
|
executables: []
|
@@ -39,6 +55,7 @@ files:
|
|
39
55
|
- README.md
|
40
56
|
- lib/rspec_parallel.rb
|
41
57
|
- lib/rspec_parallel/color_helper.rb
|
58
|
+
- lib/rspec_parallel/report_helper.rb
|
42
59
|
- lib/rspec_parallel/version.rb
|
43
60
|
- rspec_parallel.gemspec
|
44
61
|
- spec/smoke_test_spec.rb
|