rspec_parallel 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+ gemspec
3
+
4
+ gem "rake"
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rspec_parallel (0.1.0)
5
+ progressbar (>= 0.11.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ progressbar (0.11.0)
11
+ rake (0.9.2.2)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ rake
18
+ rspec_parallel!
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ rspec_parallel
2
+ ==============
3
+
4
+ run rspec examples in parallel
5
+ rspec_parallel user manual
6
+ ================
7
+
8
+ What is rspec_parallel
9
+ ------------
10
+
11
+ rspec_parallel is a ruby gem that allows to run rspec examples/tests in parallel.
12
+ 1. Tests are distributed dynamically for each thread
13
+ 2. Tests are executed alphabetically, rewrite RspecParallel.reorder_tests to change
14
+ 3. Junit-format xml report is generated after each run
15
+ 4. Re-run failures are supported
16
+ 5. Integrate progressbar gem to show the execution progress
17
+
18
+ ## Dependencies
19
+ 1. progressbar >= 0.11.0
20
+
21
+ ## _Tested Operating Systems_
22
+ 1. Mac OS X 64bit, 10.6 and above
23
+ 2. Ubuntu 10.04 LTS 64bit
24
+
25
+ Usage
26
+ -------------
27
+ 1. gem install rspec_parallel (or add it into Gemfile)
28
+ 2. Sample code:
29
+
30
+ ```
31
+ require 'rspec_parallel'
32
+
33
+ options = {}
34
+ options[:thread_number] = 4 # default: 10
35
+ options[:env_list] = [] # you can pass different env vars to each thead
36
+ options[:filter] = {"tags" => "mysql,~slow", "pattern" => /(ruby|java)/} # filter tests by tags or regular expressions
37
+ options[:show_pending] = true # show all pending tests after the run
38
+ options[:rerun] = true # rerun failures of last run
39
+ options[:single_report] = true # for rerun, update a single report; if set to false, generate separate reports.
40
+
41
+ # all supported options and default values
42
+ # @options = {:thread_number => 4, :case_folder => "./spec/", :report_folder => "./reports/",
43
+ # :filter => {}, :env_list => [], :show_pending => false, :rerun => false,
44
+ # :single_report => false, :max_rerun_times => 10, :max_thread_number => 16,
45
+ # :longevity_time => 0}.merge(options)
46
+ #
47
+
48
+ rp = RspecParallel.new(options)
49
+ rp.run_tests
50
+ ```
@@ -0,0 +1,22 @@
1
+ # Displaying text in color
2
+ module RParallel
3
+ module ColorHelpers
4
+
5
+ def red(text)
6
+ "\e[31m#{text}\e[0m"
7
+ end
8
+
9
+ def green(text)
10
+ "\e[32m#{text}\e[0m"
11
+ end
12
+
13
+ def yellow(text)
14
+ "\e[33m#{text}\e[0m"
15
+ end
16
+
17
+ def cyan(text)
18
+ "\e[36m#{text}\e[0m"
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module RParallel
2
+ VERSION = '0.1.6'
3
+ end
@@ -1,13 +1,17 @@
1
1
  #encoding: UTF-8
2
2
  $LOAD_PATH << File.dirname(__FILE__)
3
3
  require 'progressbar'
4
- require 'color_helper'
5
4
  require 'thread'
5
+ require 'find'
6
6
  require 'rexml/document'
7
7
  include REXML
8
- include ColorHelpers
9
8
 
10
- class Rspec_parallel
9
+ require 'rspec_parallel/color_helper'
10
+ require 'rspec_parallel/version'
11
+ include RParallel
12
+ include RParallel::ColorHelpers
13
+
14
+ class RspecParallel
11
15
 
12
16
  attr_reader :case_number
13
17
  attr_reader :failure_number
@@ -22,11 +26,13 @@ class Rspec_parallel
22
26
  def initialize(options = {})
23
27
  @options = {:thread_number => 4, :case_folder => "./spec/", :report_folder => "./reports/",
24
28
  :filter => {}, :env_list => [], :show_pending => false, :rerun => false,
25
- :separate_rerun_report => true, :max_rerun_times => 10, :max_thread_number => 16}.merge(options)
29
+ :single_report => false, :max_rerun_times => 10, :max_thread_number => 16,
30
+ :longevity_time => 0}.merge(options)
26
31
  @thread_number = @options[:thread_number]
27
32
  @max_rerun_times = @options[:max_rerun_times]
28
33
  @max_thread_number = @options[:max_thread_number]
29
34
 
35
+ @longevity = @options[:longevity_time]
30
36
  @case_number = 0
31
37
  @failure_number = 0
32
38
  @pending_number = 0
@@ -38,27 +44,33 @@ class Rspec_parallel
38
44
  @queue = Queue.new # store all tests to run
39
45
  @case_info_list = [] # store results of all tests
40
46
  @lock = Mutex.new # use lock to avoid output mess up
47
+ @return_message = "ok"
41
48
 
42
49
  if @thread_number < 1
43
- puts red("thread_number can't be less than 1")
44
- exit(1)
50
+ @return_message = "thread_number can't be less than 1"
51
+ puts red(@return_message)
52
+ return @return_message
45
53
  elsif @thread_number > @max_thread_number
46
- puts red("thread_number can't be greater than #{@max_thread_number}")
47
- return
54
+ @return_message = "thread_number can't be greater than #{@max_thread_number}"
55
+ puts red(@return_message)
56
+ return @return_message
48
57
  end
49
58
  puts yellow("threads number: #{@thread_number}\n")
50
59
 
51
60
  rerun = @options[:rerun]
52
- separate_rerun_report = @options[:separate_rerun_report]
53
- if rerun && separate_rerun_report
54
- @report_folder = get_rerun_folder(true)
55
- if @report_folder.include? "rerun#{@max_rerun_times + 1}"
56
- puts yellow("rerun task has been executed for #{@max_rerun_times}" +
57
- " times, maybe you should start a new run")
58
- exit(1)
59
- end
60
- else
61
- @report_folder = @options[:report_folder]
61
+ single_report = @options[:single_report]
62
+
63
+ if !single_report && rerun
64
+ @report_folder = get_single_folder("rerun", true)
65
+ end
66
+
67
+ @report_folder = @options[:report_folder] if @report_folder.nil?
68
+
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
62
74
  end
63
75
 
64
76
  filter = @options[:filter]
@@ -69,8 +81,9 @@ class Rspec_parallel
69
81
  end
70
82
 
71
83
  if @queue.empty?
72
- puts yellow("no cases to run, exit.")
73
- return
84
+ @return_message = "no cases to run, exit."
85
+ puts yellow(@return_message)
86
+ return @return_message
74
87
  end
75
88
 
76
89
  pbar = ProgressBar.new("0/#{@queue.size}", @queue.size, $stdout)
@@ -172,14 +185,16 @@ class Rspec_parallel
172
185
  end
173
186
  end
174
187
 
175
- generate_reports(end_time - start_time, rerun && !separate_rerun_report)
188
+ #CI: true - update ; default: false - new file
189
+ generate_reports(end_time - start_time, rerun && single_report)
190
+
191
+ @return_message
176
192
  end
177
193
 
178
194
  def get_case_list
179
195
  case_folder = @options[:case_folder]
180
- file_list = `grep -rl '' #{case_folder}`
181
196
  case_list = []
182
- file_list.each_line { |filename|
197
+ Find.find(case_folder) { |filename|
183
198
  unless filename.include? "_spec.rb"
184
199
  next
185
200
  end
@@ -305,29 +320,31 @@ class Rspec_parallel
305
320
  }
306
321
  end
307
322
 
308
- def get_rerun_folder(get_next=false)
309
- rerun_folder = @options[:report_folder]
310
- i = @max_rerun_times
311
- while(i > 0)
312
- if File.exists? File.join(rerun_folder, "rerun#{i}")
313
- if get_next
314
- rerun_folder = File.join(rerun_folder, "rerun#{i + 1}")
315
- else
316
- rerun_folder = File.join(rerun_folder, "rerun#{i}")
317
- end
318
- break
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
319
330
  end
320
- i -= 1
321
331
  end
322
- if get_next && (rerun_folder.include? "rerun") == false
323
- rerun_folder = File.join(rerun_folder, 'rerun1')
332
+
333
+ if get_next
334
+ i = i+1
324
335
  end
325
- rerun_folder
336
+
337
+ if i == 0
338
+ return report_folder
339
+ end
340
+
341
+ folder = File.join(report_folder, folder_prefix+"#{i.to_s}")
342
+
326
343
  end
327
344
 
328
345
  def get_failed_cases
329
- if @options[:separate_rerun_report]
330
- last_report_folder = get_rerun_folder
346
+ if !@options[:single_report]
347
+ last_report_folder = get_single_folder("rerun", false)
331
348
  last_report_file_path = File.join(last_report_folder, "junitResult.xml")
332
349
  else
333
350
  last_report_file_path = File.join(@report_folder, "junitResult.xml")
@@ -380,7 +397,7 @@ class Rspec_parallel
380
397
  end
381
398
 
382
399
  def parse_case_log(str)
383
- return nil if str =~ /0 examples/
400
+ return nil unless str =~ /1 example/
384
401
  result = {}
385
402
  logs = []
386
403
  str.each_line {|l| logs << l}
@@ -471,13 +488,11 @@ class Rspec_parallel
471
488
  def generate_reports(time, update_report)
472
489
  %x[mkdir #{@report_folder}] unless File.exists? @report_folder
473
490
  @summary_report = ""
474
- @summary_report += "<?xml version='1.0' encoding='UTF-8'?>\n"
475
- @summary_report += "<result>\n"
476
- @summary_report += "<suites>\n"
477
491
 
478
492
  class_name_list = []
479
493
  @case_info_list.each do |case_info|
480
- class_name_list << case_info['class_name']
494
+ class_name = case_info['class_name']
495
+ class_name_list << class_name
481
496
  end
482
497
  class_name_list.uniq!
483
498
  class_name_list.sort!
@@ -488,26 +503,45 @@ class Rspec_parallel
488
503
  temp_case_info_list << case_info
489
504
  end
490
505
  end
491
- generate_single_file_report(temp_case_info_list)
506
+ #CI: should insert into file while single_report == true
507
+ generate_single_file_report(temp_case_info_list, @longevity > 1 && @options[:single_report])
492
508
  end
493
509
 
494
510
  if update_report
495
511
  update_ci_report
496
512
  end
497
513
 
498
- @summary_report += "</suites>\n"
499
- @summary_report += "<duration>#{time}</duration>\n"
500
- @summary_report += "<keepLongStdio>false</keepLongStdio>\n"
501
- @summary_report += "</result>\n"
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
+
502
519
 
503
520
  report_file_path = File.join(@report_folder, 'junitResult.xml')
504
- fr = File.new(report_file_path, 'w')
505
- if update_report
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')
506
534
  fr.puts @doc
507
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>"
508
540
  fr.puts @summary_report
541
+ fr.puts summary_end
509
542
  end
510
543
  fr.close
544
+
511
545
  end
512
546
 
513
547
  def update_ci_report
@@ -535,7 +569,7 @@ class Rspec_parallel
535
569
  end
536
570
  end
537
571
 
538
- def generate_single_file_report(case_info_list)
572
+ def generate_single_file_report(case_info_list, is_update)
539
573
  return if case_info_list == []
540
574
  class_name = case_info_list[0]['class_name']
541
575
  file_name = File.join(@report_folder, class_name.gsub(/:+/, '-') + '.xml')
@@ -583,24 +617,26 @@ class Rspec_parallel
583
617
  @summary_report += "<duration>#{suite_duration}</duration>\n"
584
618
  @summary_report += "<cases>\n"
585
619
 
586
- ff = File.new(file_name, 'w')
587
- ff.puts '<?xml version="1.0" encoding="UTF-8"?>'
588
- ff.puts "<testsuite name=\"#{class_name}\" tests=\"#{case_info_list.size}\" time=\"#{suite_duration}\" failures=\"#{fail_num}\" errors=\"#{error_num}\" skipped=\"#{pending_num}\">"
620
+ single_output = ""
589
621
 
590
622
  case_desc_list.each do |case_desc|
591
623
  i = case_info_list.index {|c| c['test_desc'] == case_desc}
592
624
  case_info = case_info_list[i]
593
- test_name = case_info['test_name']
625
+ if @longevity == 0
626
+ test_name = case_info['test_name']
627
+ else
628
+ test_name = "#{@longevity}-"+case_info['test_name']
629
+ end
594
630
  test_name += " (PENDING)" if case_info['status'] == 'pending'
595
631
  test_name = test_name.encode({:xml => :attr})
596
632
  @summary_report += "<case>\n"
597
633
  @summary_report += "<duration>#{case_info['duration']}</duration>\n"
598
- @summary_report += "<className>#{case_info['class_name']}</className>\n"
634
+ @summary_report += "<className>#{class_name}</className>\n"
599
635
  @summary_report += "<testName>#{test_name}</testName>\n"
600
636
  @summary_report += "<skipped>#{case_info['status'] == 'pending'}</skipped>\n"
601
637
 
602
- ff.puts "<testcase name=#{test_name} time=\"#{case_info['duration']}\">"
603
- ff.puts "<skipped/>" if case_info['status'] == 'pending'
638
+ single_output += "<testcase name=#{test_name} time=\"#{case_info['duration']}\">\n"
639
+ single_output += "<skipped/>\n" if case_info['status'] == 'pending'
604
640
 
605
641
  if case_info['status'] == 'fail'
606
642
  @summary_report += "<errorStackTrace>\n"
@@ -619,28 +655,46 @@ class Rspec_parallel
619
655
  else
620
656
  type = "UnknownError"
621
657
  end
622
- ff.puts "<failure type=\"#{type}\" message=#{case_info['error_details'].encode({:xml => :attr})}>"
623
- ff.puts case_info['error_message'].encode({:xml => :text}).gsub('Failure/Error: ', '')
624
- ff.puts case_info['error_stack_trace'].encode({:xml => :text}).gsub('# ', '')
625
- ff.puts "</failure>"
626
- ff.puts "<rerunCommand>#{case_info['rerun_cmd'].encode({:xml => :text})}</rerunCommand>"
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"
627
663
  end
628
664
  @summary_report += "<failedSince>0</failedSince>\n"
629
665
  @summary_report += "</case>\n"
630
666
 
631
- ff.puts "</testcase>"
667
+ single_output += "</testcase>\n"
632
668
  end
633
669
 
634
670
  @summary_report += "</cases>\n"
635
671
  @summary_report += "</suite>"
636
-
637
- ff.puts "<system-out>"
638
- ff.puts stdout.encode({:xml => :text}) if stdout.length > 0
639
- ff.puts "</system-out>"
640
- ff.puts "<system-err>"
641
- ff.puts stderr.encode({:xml => :text}) if stderr.length > 0
642
- ff.puts "</system-err>"
643
- ff.puts "</testsuite>"
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
644
697
  ff.close
698
+
645
699
  end
646
700
  end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + "/lib/rspec_parallel/version"
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'rspec_parallel'
5
+ s.version = RParallel::VERSION
6
+ s.platform = Gem::Platform::RUBY
7
+ s.summary = "rspec parallel"
8
+ s.description = "parallel all rspec examples"
9
+ s.author = "VMware"
10
+ s.email = "support@vmware.com"
11
+ s.homepage = "http://www.vmware.com"
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.add_dependency('progressbar', '>=0.11.0')
15
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/../lib/rspec_parallel'
2
+
3
+ describe "smoke test for rspec_parallel" do
4
+
5
+ it "no case to run" do
6
+ options = {}
7
+ options[:case_folder] = "../lib"
8
+ rp = RspecParallel.new(options)
9
+ response = rp.run_tests
10
+ response.should == "no cases to run, exit."
11
+ end
12
+
13
+ end
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.5
4
+ version: 0.1.6
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: 2012-12-07 00:00:00.000000000 Z
12
+ date: 2012-12-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: progressbar
@@ -33,8 +33,15 @@ executables: []
33
33
  extensions: []
34
34
  extra_rdoc_files: []
35
35
  files:
36
+ - Gemfile
37
+ - Gemfile.lock
38
+ - LICENSE
39
+ - README.md
36
40
  - lib/rspec_parallel.rb
37
- - lib/color_helper.rb
41
+ - lib/rspec_parallel/color_helper.rb
42
+ - lib/rspec_parallel/version.rb
43
+ - rspec_parallel.gemspec
44
+ - spec/smoke_test_spec.rb
38
45
  homepage: http://www.vmware.com
39
46
  licenses: []
40
47
  post_install_message:
data/lib/color_helper.rb DELETED
@@ -1,20 +0,0 @@
1
- # Displaying text in color
2
- module ColorHelpers
3
-
4
- def red(text)
5
- "\e[31m#{text}\e[0m"
6
- end
7
-
8
- def green(text)
9
- "\e[32m#{text}\e[0m"
10
- end
11
-
12
- def yellow(text)
13
- "\e[33m#{text}\e[0m"
14
- end
15
-
16
- def cyan(text)
17
- "\e[36m#{text}\e[0m"
18
- end
19
-
20
- end