parallelized_specs 0.3.23 → 0.3.24

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/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