parallelized_specs 0.3.23 → 0.3.24

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ begin
12
12
  gem.email = "jake@instructure.com"
13
13
  gem.homepage = "http://github.com/jakesorce/#{gem.name}"
14
14
  gem.authors = "Jake Sorce, Bryan Madsen, Shawn Meredith"
15
- gem.version = "0.3.23"
15
+ gem.version = "0.3.24"
16
16
  end
17
17
  Jeweler::GemcutterTasks.new
18
18
  rescue LoadError
@@ -95,172 +95,221 @@ class ParallelizedSpecs
95
95
  end
96
96
  groups = tests_in_groups(files_array || tests || tests_folder, num_processes, options)
97
97
 
98
- num_processes = groups.size
98
+ num_processes = groups.size
99
99
 
100
- #adjust processes to groups
101
- abort "no #{name}s found!" if groups.size == 0
100
+ #adjust processes to groups
101
+ abort "no #{name}s found!" if groups.size == 0
102
102
 
103
- num_tests = groups.inject(0) { |sum, item| sum + item.size }
104
- puts "#{num_processes} processes for #{num_tests} #{name}s, ~ #{num_tests / groups.size} #{name}s per process"
103
+ num_tests = groups.inject(0) { |sum, item| sum + item.size }
104
+ puts "#{num_processes} processes for #{num_tests} #{name}s, ~ #{num_tests / groups.size} #{name}s per process"
105
105
 
106
- test_results = Parallel.map(groups, :in_processes => num_processes) do |group|
107
- run_tests(group, groups.index(group), options)
108
- end
106
+ test_results = Parallel.map(groups, :in_processes => num_processes) do |group|
107
+ run_tests(group, groups.index(group), options)
108
+ end
109
109
 
110
- #parse and print results
111
- results = find_results(test_results.map { |result| result[:stdout] }*"")
112
- puts ""
113
- puts summarize_results(results)
110
+ #parse and print results
111
+ results = find_results(test_results.map { |result| result[:stdout] }*"")
112
+ puts ""
113
+ puts summarize_results(results)
114
114
 
115
- #report total time taken
116
- puts ""
117
- puts "Took #{Time.now - start} seconds"
115
+ #report total time taken
116
+ puts ""
117
+ puts "Took #{Time.now - start} seconds"
118
118
 
119
- #exit with correct status code so rake parallel:test && echo 123 works
120
- failed = test_results.any? { |result| result[:exit_status] != 0 }
121
- abort "#{name.capitalize}s Failed" if failed
122
- end
119
+ #exit with correct status code so rake parallel:test && echo 123 works
120
+ failed = test_results.any? { |result| result[:exit_status] != 0 }
121
+ abort "#{name.capitalize}s Failed" if failed
122
+ end
123
123
 
124
124
  # parallel:spec[:count, :pattern, :options]
125
- def self.parse_rake_args(args)
126
- # order as given by user
127
- args = [args[:count], args[:pattern]]
125
+ def self.parse_rake_args(args)
126
+ # order as given by user
127
+ args = [args[:count], args[:pattern]]
128
128
 
129
- # count given or empty ?
130
- count = args.shift if args.first.to_s =~ /^\d*$/
131
- num_processes = count.to_i unless count.to_s.empty?
132
- num_processes ||= ENV['PARALLEL_TEST_PROCESSORS'].to_i if ENV['PARALLEL_TEST_PROCESSORS']
133
- num_processes ||= Parallel.processor_count
129
+ # count given or empty ?
130
+ count = args.shift if args.first.to_s =~ /^\d*$/
131
+ num_processes = count.to_i unless count.to_s.empty?
132
+ num_processes ||= ENV['PARALLEL_TEST_PROCESSORS'].to_i if ENV['PARALLEL_TEST_PROCESSORS']
133
+ num_processes ||= Parallel.processor_count
134
134
 
135
- pattern = args.shift
135
+ pattern = args.shift
136
136
 
137
- [num_processes.to_i, pattern.to_s]
138
- end
137
+ [num_processes.to_i, pattern.to_s]
138
+ end
139
139
 
140
140
  # finds all tests and partitions them into groups
141
- def self.tests_in_groups(tests, num_groups, options)
142
- if options[:no_sort]
143
- Grouper.in_groups(tests, num_groups)
144
- else
145
- tests = with_runtime_info(tests)
146
- Grouper.in_even_groups_by_size(tests, num_groups, options)
141
+ def self.tests_in_groups(tests, num_groups, options)
142
+ if options[:no_sort]
143
+ Grouper.in_groups(tests, num_groups)
144
+ else
145
+ tests = with_runtime_info(tests)
146
+ Grouper.in_even_groups_by_size(tests, num_groups, options)
147
+ end
147
148
  end
148
- end
149
-
150
- def self.execute_command(cmd, process_number, options)
151
- cmd = "TEST_ENV_NUMBER=#{test_env_number(process_number)} ; export TEST_ENV_NUMBER; #{cmd}"
152
- f = open("|#{cmd}", 'r')
153
- output = fetch_output(f, options)
154
- f.close
155
- {:stdout => output, :exit_status => $?.exitstatus}
156
- end
157
-
158
- def self.find_results(test_output)
159
- test_output.split("\n").map { |line|
160
- line = line.gsub(/\.|F|\*/, '')
161
- next unless line_is_result?(line)
162
- line
163
- }.compact
164
- end
165
-
166
- def self.test_env_number(process_number)
167
- process_number == 0 ? '' : process_number + 1
168
- end
169
-
170
- def self.runtime_log
171
- 'tmp/parallelized_runtime_test.log'
172
- end
173
-
174
- def self.summarize_results(results)
175
- results = results.join(' ').gsub(/s\b/, '') # combine and singularize results
176
- counts = results.scan(/(\d+) (\w+)/)
177
- sums = counts.inject(Hash.new(0)) do |sum, (number, word)|
178
- sum[word] += number.to_i
179
- sum
149
+
150
+ def self.execute_command(cmd, process_number, options)
151
+ cmd = "TEST_ENV_NUMBER=#{test_env_number(process_number)} ; export TEST_ENV_NUMBER; #{cmd}"
152
+ f = open("|#{cmd}", 'r')
153
+ output = fetch_output(f, options)
154
+ f.close
155
+ {:stdout => output, :exit_status => $?.exitstatus}
180
156
  end
181
- sums.sort.map { |word, number| "#{number} #{word}#{'s' if number != 1}" }.join(', ')
182
- end
183
157
 
184
- protected
158
+ def self.find_results(test_output)
159
+ test_output.split("\n").map { |line|
160
+ line = line.gsub(/\.|F|\*/, '')
161
+ next unless line_is_result?(line)
162
+ line
163
+ }.compact
164
+ end
185
165
 
186
- # read output of the process and print in in chucks
187
- def self.fetch_output(process, options)
188
- all = ''
189
- buffer = ''
190
- timeout = options[:chunk_timeout] || 0.2
191
- flushed = Time.now.to_f
192
-
193
- while (char = process.getc)
194
- char = (char.is_a?(Fixnum) ? char.chr : char) # 1.8 <-> 1.9
195
- all << char
196
-
197
- # print in chunks so large blocks stay together
198
- now = Time.now.to_f
199
- buffer << char
200
- if flushed + timeout < now
201
- print buffer
202
- STDOUT.flush
203
- buffer = ''
204
- flushed = now
166
+ def self.test_env_number(process_number)
167
+ process_number == 0 ? '' : process_number + 1
168
+ end
169
+
170
+ def self.runtime_log
171
+ 'tmp/parallelized_runtime_test.log'
172
+ end
173
+
174
+ def self.summarize_results(results)
175
+ results = results.join(' ').gsub(/s\b/, '') # combine and singularize results
176
+ counts = results.scan(/(\d+) (\w+)/)
177
+ sums = counts.inject(Hash.new(0)) do |sum, (number, word)|
178
+ sum[word] += number.to_i
179
+ sum
205
180
  end
181
+ sums.sort.map { |word, number| "#{number} #{word}#{'s' if number != 1}" }.join(', ')
206
182
  end
207
183
 
208
- # print the remainder
209
- print buffer
210
- STDOUT.flush
184
+ protected
185
+
186
+ # read output of the process and print in in chucks
187
+ def self.fetch_output(process, options)
188
+ all = ''
189
+ buffer = ''
190
+ timeout = options[:chunk_timeout] || 0.2
191
+ flushed = Time.now.to_f
192
+
193
+ while (char = process.getc)
194
+ char = (char.is_a?(Fixnum) ? char.chr : char) # 1.8 <-> 1.9
195
+ all << char
196
+
197
+ # print in chunks so large blocks stay together
198
+ now = Time.now.to_f
199
+ buffer << char
200
+ if flushed + timeout < now
201
+ print buffer
202
+ STDOUT.flush
203
+ buffer = ''
204
+ flushed = now
205
+ end
206
+ end
207
+
208
+ # print the remainder
209
+ print buffer
210
+ STDOUT.flush
211
211
 
212
- all
213
- end
212
+ all
213
+ end
214
214
 
215
215
  # copied from http://github.com/carlhuda/bundler Bundler::SharedHelpers#find_gemfile
216
- def self.bundler_enabled?
217
- return true if Object.const_defined?(:Bundler)
216
+ def self.bundler_enabled?
217
+ return true if Object.const_defined?(:Bundler)
218
218
 
219
- previous = nil
220
- current = File.expand_path(Dir.pwd)
219
+ previous = nil
220
+ current = File.expand_path(Dir.pwd)
221
221
 
222
- until !File.directory?(current) || current == previous
223
- filename = File.join(current, "Gemfile")
224
- return true if File.exists?(filename)
225
- current, previous = File.expand_path("..", current), current
226
- end
222
+ until !File.directory?(current) || current == previous
223
+ filename = File.join(current, "Gemfile")
224
+ return true if File.exists?(filename)
225
+ current, previous = File.expand_path("..", current), current
226
+ end
227
227
 
228
- false
229
- end
228
+ false
229
+ end
230
230
 
231
- def self.line_is_result?(line)
232
- line =~ /\d+ failure/
233
- end
231
+ def self.line_is_result?(line)
232
+ line =~ /\d+ failure/
233
+ end
234
234
 
235
- def self.with_runtime_info(tests)
236
- lines = File.read(runtime_log).split("\n") rescue []
235
+ def self.with_runtime_info(tests)
236
+ lines = File.read(runtime_log).split("\n") rescue []
237
+
238
+ # use recorded test runtime if we got enough data
239
+ if lines.size * 1.5 > tests.size
240
+ puts "Using recorded test runtime"
241
+ times = Hash.new(1)
242
+ lines.each do |line|
243
+ test, time = line.split(":")
244
+ next unless test and time
245
+ times[File.expand_path(test)] = time.to_f
246
+ end
247
+ tests.sort.map { |test| [test, times[test]] }
248
+ else # use file sizes
249
+ tests.sort.map { |test| [test, File.stat(test).size] }
250
+ end
251
+ end
237
252
 
238
- # use recorded test runtime if we got enough data
239
- if lines.size * 1.5 > tests.size
240
- puts "Using recorded test runtime"
241
- times = Hash.new(1)
242
- lines.each do |line|
243
- test, time = line.split(":")
244
- next unless test and time
245
- times[File.expand_path(test)] = time.to_f
253
+ def self.find_tests(root, options={})
254
+ if root.is_a?(Array)
255
+ root
256
+ else
257
+ # follow one symlink and direct children
258
+ # http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
259
+ files = Dir["#{root}/**{,/*/**}/*#{test_suffix}"].uniq
260
+ files = files.map { |f| f.sub(root+'/', '') }
261
+ files = files.grep(/#{options[:pattern]}/)
262
+ files.map { |f| "/#{f}" }
246
263
  end
247
- tests.sort.map { |test| [test, times[test]] }
248
- else # use file sizes
249
- tests.sort.map { |test| [test, File.stat(test).size] }
250
264
  end
251
- end
252
-
253
- def self.find_tests(root, options={})
254
- if root.is_a?(Array)
255
- root
256
- else
257
- # follow one symlink and direct children
258
- # http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
259
- files = Dir["#{root}/**{,/*/**}/*#{test_suffix}"].uniq
260
- files = files.map { |f| f.sub(root+'/', '') }
261
- files = files.grep(/#{options[:pattern]}/)
262
- files.map { |f| "/#{f}" }
265
+
266
+ def self.rerun()
267
+ rerun_failed_examples = false
268
+
269
+ if FileTest.exist?("#{RAILS_ROOT}/tmp/parallel_log/rspec.failures")
270
+ @error_count = %x{wc -l "#{FILENAME}"}.match(/\d/).to_s #counts the number of lines in the file
271
+
272
+ if @error_count.to_i > 1 && @error_count.to_i < 10
273
+ puts "rerunning #{@error_count} examples again"
274
+ @rerun_failures ||= []
275
+ @rerun_passes ||= []
276
+
277
+ File.open("#{FILENAME}").each_line do |l|
278
+ rerun_failed_examples = true
279
+ puts "#{l} will be ran and marked as a success if it passes"
280
+ result = %x[bundle exec rake spec #{l}]
281
+ rerun_status = result.match(/FAILED/).to_s
282
+
283
+ if rerun_status == "FAILED"
284
+ puts "the example failed again"
285
+ @rerun_failures << l
286
+ rerun_status = ""
287
+ else
288
+ puts "the example passed and is being marked as a success"
289
+ @rerun_passes << l
290
+ rerun_status = ""
291
+ end
292
+ end #end file loop
293
+ end
294
+
295
+ if rerun_failed_examples
296
+ if @rerun_failures.count > 0
297
+ puts "1 or more examples failed on rerun, rspec will mark this build as a failure"
298
+ #dump errors to file
299
+ exit(1)
300
+ elsif @rerun_passes.count >= @error_count.to_i
301
+ puts "all rerun examples passed, rspec will mark this build as passed"
302
+ $rerun_success = true
303
+ exit(0)
304
+ else
305
+ put "something unexpected happened not safe to mark the build as passed."
306
+ exit(1)
307
+ end
308
+ end
309
+ end
310
+ else
311
+ "No errors file was found, marking build as a success"
312
+ exit(0)
313
+ end
263
314
  end
264
- end
265
315
 
266
- end
@@ -7,7 +7,7 @@ class ParallelizedSpecs::ExampleRerunFailuresLogger < ParallelizedSpecs::SpecLog
7
7
  if example.location != nil
8
8
  unless !!self.example_group.nested_descriptions.to_s.match(/shared/) || !!self.instance_variable_get(:@example_group).examples.last.location.match(/helper/)
9
9
  @failed_examples ||= []
10
- @failed_examples << "#{example.location.match(/spec.*\d/).to_s.chomp}"
10
+ @failed_examples << "#{example.location.match(/spec.*\d/).to_s.chomp} "
11
11
  end
12
12
  end
13
13
  else
@@ -3,9 +3,7 @@ require 'parallelized_specs/spec_logger_base'
3
3
 
4
4
  module RSpec
5
5
  class ParallelizedSpecs::FailuresFormatter < ParallelizedSpecs::SpecLoggerBase
6
- #env_test_number = ENV['TEST_ENV_NUMBER']
7
- #env_test_number = 1 if ENV['TEST_ENV_NUMBER'].nil
8
- FILENAME = "#{RAILS_ROOT}/rspec.failures"
6
+ FILENAME = "#{RAILS_ROOT}/tmp/parallel_log/rspec.failures"
9
7
 
10
8
  def example_failed(example, counter, failure)
11
9
  @rerun_examples ||= []
@@ -15,41 +13,6 @@ module RSpec
15
13
  end
16
14
 
17
15
  def dump_summary(*args)
18
- rerun_failed_examples = false
19
- @rerun_failures ||= []
20
- @rerun_passes ||= []
21
- @error_count = %x{wc -l "#{FILENAME}"}.match(/\d/).to_s #counts the number of lines in the file
22
-
23
- if @error_count.to_i > 1 && @error_count.to_i < 10
24
- @output.puts "rerunning #{@error_count} examples again"
25
- File.open("#{FILENAME}").each_line do |l|
26
- rerun_failed_examples = true
27
- @output.puts "#{l} will be ran and marked as a success if it passes"
28
- result = %x[bundle exec rake spec #{l}]
29
- rerun_status = result.match(/FAILED/).to_s
30
-
31
- if rerun_status == "FAILED"
32
- @output.puts "the example failed again"
33
- @rerun_failures << l
34
- rerun_status = ""
35
- else
36
- @output.puts "the example passed and is being marked as a success"
37
- @rerun_passes << l
38
- rerun_status = ""
39
- end
40
- end #end file loop
41
- end
42
-
43
- if rerun_failed_examples
44
- if @rerun_failures.length > 0
45
- @output.puts "1 or more examples failed on rerun, rspec will mark this build as a failure"
46
- else
47
- @output.puts "all rerun examples passed, rspec will mark this build as passed"
48
- $rerun_success = true
49
- Spec::Runner.options.instance_variable_get(:@reporter).instance_variable_get(:@failures).delete_if { |item| item != 'b' } #placeholder delete all failures in array approach
50
- end
51
- else
52
- end
53
16
  end
54
17
 
55
18
  def dump_failures(*args)
@@ -44,9 +44,14 @@ namespace :parallel do
44
44
  end
45
45
 
46
46
  desc "run spec in parallel with parallel:spec[num_cpus]"
47
- task 'spec', :count, :pattern, :options, :arguments do |t, args|
48
- count, pattern = ParallelizedSpecs.parse_rake_args(args)
49
- opts = {:count => count, :pattern => pattern, :root => Rails.root, :files => args[:arguments]}
50
- ParallelizedSpecs.execute_parallel_specs(opts)
47
+ task 'spec', :count, :pattern, :options, :arguments do |t, args|
48
+ count, pattern = ParallelizedSpecs.parse_rake_args(args)
49
+ opts = {:count => count, :pattern => pattern, :root => Rails.root, :files => args[:arguments]}
50
+ ParallelizedSpecs.execute_parallel_specs(opts)
51
+ end
52
+
53
+ desc "reruns all the failed specs in 1 thread"
54
+ task 'rerun' do
55
+ ParallelizedSpecs.rerun()
51
56
  end
52
57
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "parallelized_specs"
8
- s.version = "0.3.23"
8
+ s.version = "0.3.24"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jake Sorce, Bryan Madsen, Shawn Meredith"]
12
- s.date = "2012-10-29"
12
+ s.date = "2012-10-30"
13
13
  s.email = "jake@instructure.com"
14
14
  s.files = [
15
15
  "Gemfile",
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallelized_specs
3
3
  version: !ruby/object:Gem::Version
4
- hash: 61
4
+ hash: 35
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 23
10
- version: 0.3.23
9
+ - 24
10
+ version: 0.3.24
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jake Sorce, Bryan Madsen, Shawn Meredith
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-10-29 00:00:00 Z
18
+ date: 2012-10-30 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: parallel