parallel_tests 0.4.20 → 0.4.21

Sign up to get free protection for your applications and to get access to all the features.
data/Readme.md CHANGED
@@ -1,4 +1,4 @@
1
- Speedup Test::Unit + RSpec + Cucumber by running parallel on multiple CPUs(or cores).
1
+ Speedup Test::Unit + RSpec + Cucumber by running parallel on multiple CPUs (or cores).
2
2
 
3
3
  Setup for Rails
4
4
  ===============
@@ -59,6 +59,7 @@ OR as plugin
59
59
  ...
60
60
 
61
61
  Test just a subfolder (e.g. use one integration server per subfolder)
62
+
62
63
  rake parallel:test[models]
63
64
  rake parallel:test[something/else]
64
65
 
@@ -76,10 +77,14 @@ Example output
76
77
 
77
78
  Took 29.925333 seconds
78
79
 
79
- Even process runtimes (for specs only)
80
+ Spec Loggers
81
+ ===================
82
+
83
+ Even process runtimes
80
84
  -----------------
81
85
 
82
- Log test runtime to give each process the same test runtime.<br/>
86
+ Log test runtime to give each process the same test runtime.
87
+
83
88
  Add to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
84
89
 
85
90
  RSpec 1.x:
@@ -90,6 +95,36 @@ Add to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
90
95
  --format progress
91
96
  --format ParallelSpecs::SpecRuntimeLogger --out tmp/parallel_profile.log
92
97
 
98
+ SpecSummaryLogger
99
+ --------------------
100
+
101
+ This logger stops the different processes overwriting each other's output.
102
+
103
+ Add the following to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
104
+
105
+ RSpec 1.x:
106
+ --format progress
107
+ --format ParallelSpecs::SpecSummaryLogger:tmp/spec_summary.log
108
+ RSpec >= 2.2:
109
+ --format progress
110
+ --format ParallelSpecs::SpecSummaryLogger --out tmp/spec_summary.log
111
+
112
+ SpecFailuresLogger
113
+ -----------------------
114
+
115
+ This logger produces command lines for running any failing examples.
116
+
117
+ E.g.
118
+
119
+ spec /path/to/my_spec.rb -e "should do something"
120
+
121
+ Add the following to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
122
+
123
+ RSpec 1.x:
124
+ --format ParallelSpecs::SpecFailuresLogger:tmp/failing_specs.log
125
+ RSpec >= 2.2:
126
+ --format ParallelSpecs::SpecFailuresLogger --out tmp/failing_specs.log
127
+
93
128
  Setup for non-rails
94
129
  ===================
95
130
  sudo gem install parallel_tests
@@ -98,9 +133,11 @@ Setup for non-rails
98
133
  # [Optional] use ENV['TEST_ENV_NUMBER'] inside your tests to select separate db/memcache/etc.
99
134
 
100
135
  [optional] Only run selected files & folders:
136
+
101
137
  parallel_test test/bar test/baz/xxx_text.rb
102
138
 
103
139
  Options are:
140
+
104
141
  -n [PROCESSES] How many processes to use, default: available CPUs
105
142
  -p, --path [PATH] run tests inside this path only
106
143
  --no-sort do not sort files before running them
@@ -114,6 +151,7 @@ Options are:
114
151
  -h, --help Show this.
115
152
 
116
153
  You can run any kind of code with -e / --execute
154
+
117
155
  parallel_test -n 5 -e 'ruby -e "puts %[hello from process #{ENV[:TEST_ENV_NUMBER.to_s].inspect}]"'
118
156
  hello from process "2"
119
157
  hello from process ""
@@ -169,6 +207,7 @@ inspired by [pivotal labs](http://pivotallabs.com/users/miked/blog/articles/849-
169
207
  - [Levent Ali](http://purebreeze.com/)
170
208
  - [Michael Kintzer](https://github.com/rockrep)
171
209
  - [nathansobo](https://github.com/nathansobo)
210
+ - [Joe Yates](http://titusd.co.uk)
172
211
 
173
212
  [Michael Grosser](http://grosser.it)<br/>
174
213
  michael@grosser.it<br/>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.20
1
+ 0.4.21
@@ -0,0 +1,25 @@
1
+ require 'parallel_specs'
2
+ require File.join(File.dirname(__FILE__), 'spec_logger_base')
3
+
4
+ class ParallelSpecs::SpecFailuresLogger < ParallelSpecs::SpecLoggerBase
5
+ def initialize(options, output=nil)
6
+ super
7
+ @failed_examples = []
8
+ end
9
+
10
+ def example_failed(example, count, failure)
11
+ @failed_examples << example
12
+ end
13
+
14
+ def dump_failure(*args)
15
+ lock_output do
16
+ @failed_examples.each.with_index do | example, i |
17
+ spec_file = example.location.scan(/^[^:]+/)[0]
18
+ spec_file.gsub!(%r(^.*?/spec/), './spec/')
19
+ @output.puts "#{ParallelSpecs.executable} #{spec_file} -e \"#{example.description}\""
20
+ end
21
+ end
22
+ @output.flush
23
+ end
24
+
25
+ end
@@ -0,0 +1,72 @@
1
+ require 'parallel_specs'
2
+
3
+ begin
4
+ require 'rspec/core/formatters/progress_formatter'
5
+ base = RSpec::Core::Formatters::ProgressFormatter
6
+ rescue LoadError
7
+ require 'spec/runner/formatter/progress_bar_formatter'
8
+ base = Spec::Runner::Formatter::BaseTextFormatter
9
+ end
10
+ ParallelSpecs::SpecLoggerBaseBase = base
11
+
12
+ class ParallelSpecs::SpecLoggerBase < ParallelSpecs::SpecLoggerBaseBase
13
+ def initialize(options, output=nil)
14
+ output ||= options # rspec 2 has output as first argument
15
+
16
+ if String === output
17
+ FileUtils.mkdir_p(File.dirname(output))
18
+ File.open(output, 'w'){} # overwrite previous results
19
+ @output = File.open(output, 'a')
20
+ elsif File === output
21
+ output.close # close file opened with 'w'
22
+ @output = File.open(output.path, 'a')
23
+ else
24
+ @output = output
25
+ end
26
+
27
+ @failed_examples = [] # only needed for rspec 2
28
+ end
29
+
30
+ def example_started(*args)
31
+ end
32
+
33
+ def example_passed(example)
34
+ end
35
+
36
+ def example_pending(*args)
37
+ end
38
+
39
+ def example_failed(*args)
40
+ end
41
+
42
+ def start_dump(*args)
43
+ end
44
+
45
+ def dump_summary(*args)
46
+ end
47
+
48
+ def dump_pending(*args)
49
+ end
50
+
51
+ def dump_failure(*args)
52
+ end
53
+
54
+ #stolen from Rspec
55
+ def close
56
+ @output.close if (IO === @output) & (@output != $stdout)
57
+ end
58
+
59
+ # do not let multiple processes get in each others way
60
+ def lock_output
61
+ if File === @output
62
+ begin
63
+ @output.flock File::LOCK_EX
64
+ yield
65
+ ensure
66
+ @output.flock File::LOCK_UN
67
+ end
68
+ else
69
+ yield
70
+ end
71
+ end
72
+ end
@@ -1,31 +1,10 @@
1
1
  require 'parallel_specs'
2
+ require File.join(File.dirname(__FILE__), 'spec_logger_base')
2
3
 
3
- begin
4
- require 'rspec/core/formatters/progress_formatter'
5
- base = RSpec::Core::Formatters::ProgressFormatter
6
- rescue LoadError
7
- require 'spec/runner/formatter/progress_bar_formatter'
8
- base = Spec::Runner::Formatter::BaseTextFormatter
9
- end
10
- ParallelSpecs::SpecRuntimeLoggerBase = base
11
-
12
- class ParallelSpecs::SpecRuntimeLogger < ParallelSpecs::SpecRuntimeLoggerBase
4
+ class ParallelSpecs::SpecRuntimeLogger < ParallelSpecs::SpecLoggerBase
13
5
  def initialize(options, output=nil)
14
- output ||= options # rspec 2 has output as first argument
15
-
16
- if String === output
17
- FileUtils.mkdir_p(File.dirname(output))
18
- File.open(output, 'w'){} # overwrite previous results
19
- @output = File.open(output, 'a')
20
- elsif File === output
21
- output.close # close file opened with 'w'
22
- @output = File.open(output.path, 'a')
23
- else
24
- @output = output
25
- end
26
-
6
+ super
27
7
  @example_times = Hash.new(0)
28
- @failed_examples = [] # only needed for rspec 2
29
8
  end
30
9
 
31
10
  def example_started(*args)
@@ -46,39 +25,4 @@ class ParallelSpecs::SpecRuntimeLogger < ParallelSpecs::SpecRuntimeLoggerBase
46
25
  @output.flush
47
26
  end
48
27
 
49
- # stubs so that rspec doe not crash
50
-
51
- def example_pending(*args)
52
- end
53
-
54
- def example_failed(*args)
55
- end
56
-
57
- def dump_summary(*args)
58
- end
59
-
60
- def dump_pending(*args)
61
- end
62
-
63
- def dump_failure(*args)
64
- end
65
-
66
- #stolen from Rspec
67
- def close
68
- @output.close if (IO === @output) & (@output != $stdout)
69
- end
70
-
71
- # do not let multiple processes get in each others way
72
- def lock_output
73
- if File === @output
74
- begin
75
- @output.flock File::LOCK_EX
76
- yield
77
- ensure
78
- @output.flock File::LOCK_UN
79
- end
80
- else
81
- yield
82
- end
83
- end
84
28
  end
@@ -0,0 +1,47 @@
1
+ require 'parallel_specs'
2
+ require File.join(File.dirname(__FILE__), 'spec_logger_base')
3
+
4
+ class ParallelSpecs::SpecSummaryLogger < ParallelSpecs::SpecLoggerBase
5
+ def initialize(options, output=nil)
6
+ super
7
+ @passed_examples = []
8
+ @pending_examples = []
9
+ @failed_examples = []
10
+ end
11
+
12
+ def example_passed(example)
13
+ @passed_examples << example
14
+ end
15
+
16
+ def example_pending(*args)
17
+ @pending_examples << args
18
+ end
19
+
20
+ def example_failed(example, count, failure)
21
+ @failed_examples << failure
22
+ end
23
+
24
+ def dump_summary(duration, example_count, failure_count, pending_count)
25
+ lock_output do
26
+ @output.puts "#{ @passed_examples.size } examples passed"
27
+ end
28
+ @output.flush
29
+ end
30
+
31
+ def dump_failure(*args)
32
+ lock_output do
33
+ @output.puts "#{ @failed_examples.size } examples failed:"
34
+ @failed_examples.each.with_index do | failure, i |
35
+ @output.puts "#{ i + 1 })"
36
+ @output.puts failure.header
37
+ @output.puts failure.exception.to_s
38
+ failure.exception.backtrace.each do | caller |
39
+ @output.puts caller
40
+ end
41
+ @output.puts ''
42
+ end
43
+ end
44
+ @output.flush
45
+ end
46
+
47
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{parallel_tests}
8
- s.version = "0.4.20"
8
+ s.version = "0.4.21"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Grosser"]
12
- s.date = %q{2011-06-04}
12
+ s.date = %q{2011-06-12}
13
13
  s.email = %q{grosser.michael@gmail.com}
14
14
  s.executables = ["parallel_cucumber", "parallel_spec", "parallel_test"]
15
15
  s.files = [
@@ -25,7 +25,10 @@ Gem::Specification.new do |s|
25
25
  "lib/parallel_cucumber.rb",
26
26
  "lib/parallel_cucumber/runtime_logger.rb",
27
27
  "lib/parallel_specs.rb",
28
+ "lib/parallel_specs/spec_failures_logger.rb",
29
+ "lib/parallel_specs/spec_logger_base.rb",
28
30
  "lib/parallel_specs/spec_runtime_logger.rb",
31
+ "lib/parallel_specs/spec_summary_logger.rb",
29
32
  "lib/parallel_tests.rb",
30
33
  "lib/parallel_tests/grouper.rb",
31
34
  "lib/parallel_tests/railtie.rb",
@@ -1,4 +1,7 @@
1
1
  require 'spec/spec_helper'
2
+ require 'parallel_specs/spec_runtime_logger'
3
+ require 'parallel_specs/spec_summary_logger'
4
+ require 'parallel_specs/spec_failures_logger'
2
5
 
3
6
  describe ParallelSpecs do
4
7
  test_tests_in_groups(ParallelSpecs, 'spec', '_spec.rb')
@@ -160,4 +163,103 @@ EOF
160
163
  ParallelSpecs.find_results(output).should == ['0 examples, 0 failures, 0 pending','1 examples, 1 failures, 1 pending']
161
164
  end
162
165
  end
166
+
167
+ context "logging" do
168
+
169
+ OutputLogger = Struct.new(:output) do
170
+ attr_reader :flock, :flush
171
+ def puts(s)
172
+ self.output << s
173
+ end
174
+ end
175
+
176
+ before :each do
177
+ @output = OutputLogger.new([])
178
+ @example1 = mock( 'example', :location => '/my/spec/path/to/example:123', :description => 'should do stuff' )
179
+ @example2 = mock( 'example', :location => '/my/spec/path/to/example2:456', :description => 'should do other stuff' )
180
+ @exception1 = mock( :to_s => 'exception', :backtrace => [ '/path/to/error/line:33' ] )
181
+ @failure1 = mock( 'example', :location => '/path/to/example:123', :header => 'header', :exception => @exception1 )
182
+ end
183
+
184
+ describe ParallelSpecs::SpecRuntimeLogger do
185
+ before :each do
186
+ ENV['TEST_ENV_NUMBER'] = '1'
187
+ @logger = ParallelSpecs::SpecRuntimeLogger.new( @output )
188
+ end
189
+
190
+ it "collects runtime information" do
191
+ @logger.example_started
192
+ @logger.example_passed( @example1 )
193
+
194
+ @logger.start_dump
195
+
196
+ @output.output.size.should == 1
197
+ @output.output[0].size.should == 1
198
+ @output.output[0][0].should =~ %r(/path/to/example:([\d\.e\-]+))
199
+ end
200
+ end
201
+
202
+ describe ParallelSpecs::SpecSummaryLogger do
203
+ before :each do
204
+ @logger = ParallelSpecs::SpecSummaryLogger.new( @output )
205
+ end
206
+
207
+ it "should print a summary of failing examples" do
208
+ @logger.example_failed( nil, nil, @failure1 )
209
+
210
+ @logger.dump_failure
211
+
212
+ @output.output.should == ["1 examples failed:", "1)", "header", "exception", "/path/to/error/line:33", ""]
213
+ end
214
+ end
215
+
216
+ describe ParallelSpecs::SpecFailuresLogger do
217
+ before :each do
218
+ @logger = ParallelSpecs::SpecFailuresLogger.new( @output )
219
+ end
220
+
221
+ it "should produce a list of command lines for failing examples" do
222
+ @logger.example_failed( @example1, nil, nil )
223
+ @logger.example_failed( @example2, nil, nil )
224
+
225
+ @logger.dump_failure
226
+
227
+ @output.output.size.should == 2
228
+ @output.output[0].should =~ /r?spec .*? -e "should do stuff"/
229
+ @output.output[1].should =~ /r?spec .*? -e "should do other stuff"/
230
+ end
231
+
232
+ it "should invoke spec for rspec 1" do
233
+ ParallelSpecs.stub!(:bundler_enabled?).and_return true
234
+ ParallelSpecs.stub!(:run).with("bundle show rspec").and_return "/foo/bar/rspec-1.0.2"
235
+ @logger.example_failed( @example1, nil, nil )
236
+
237
+ @logger.dump_failure
238
+
239
+ @output.output[0].should =~ /^bundle exec spec/
240
+ end
241
+
242
+ it "should invoke rspec for rspec 2" do
243
+ ParallelSpecs.stub!(:bundler_enabled?).and_return true
244
+ ParallelSpecs.stub!(:run).with("bundle show rspec").and_return "/foo/bar/rspec-2.0.2"
245
+ @logger.example_failed( @example1, nil, nil )
246
+
247
+ @logger.dump_failure
248
+
249
+ @output.output[0].should =~ /^bundle exec rspec/
250
+ end
251
+
252
+ it "should return relative paths" do
253
+ @logger.example_failed( @example1, nil, nil )
254
+ @logger.example_failed( @example2, nil, nil )
255
+
256
+ @logger.dump_failure
257
+
258
+ @output.output[0].should =~ %r(\./spec/path/to/example)
259
+ @output.output[1].should =~ %r(\./spec/path/to/example2)
260
+ end
261
+
262
+ end
263
+
264
+ end
163
265
  end
@@ -54,10 +54,14 @@ def test_tests_in_groups(klass, folder, suffix)
54
54
  end
55
55
 
56
56
  @log = klass.runtime_log
57
- `mkdir #{File.dirname(@log)}`
57
+ `mkdir -p #{File.dirname(@log)}`
58
58
  `rm -f #{@log}`
59
59
  end
60
60
 
61
+ after :all do
62
+ `rm -f #{klass.runtime_log}`
63
+ end
64
+
61
65
  it "groups when given an array of files" do
62
66
  list_of_files = Dir["#{test_root}/**/*#{suffix}"]
63
67
  found = klass.tests_with_runtime(list_of_files)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel_tests
3
3
  version: !ruby/object:Gem::Version
4
- hash: 39
4
+ hash: 37
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 4
9
- - 20
10
- version: 0.4.20
9
+ - 21
10
+ version: 0.4.21
11
11
  platform: ruby
12
12
  authors:
13
13
  - Michael Grosser
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-04 00:00:00 +02:00
18
+ date: 2011-06-12 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -55,7 +55,10 @@ files:
55
55
  - lib/parallel_cucumber.rb
56
56
  - lib/parallel_cucumber/runtime_logger.rb
57
57
  - lib/parallel_specs.rb
58
+ - lib/parallel_specs/spec_failures_logger.rb
59
+ - lib/parallel_specs/spec_logger_base.rb
58
60
  - lib/parallel_specs/spec_runtime_logger.rb
61
+ - lib/parallel_specs/spec_summary_logger.rb
59
62
  - lib/parallel_tests.rb
60
63
  - lib/parallel_tests/grouper.rb
61
64
  - lib/parallel_tests/railtie.rb