moxiesoft_parallel_tests 0.4.12

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.sh
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :rubygems
2
+
3
+ gem 'parallel'
4
+
5
+ group :dev do
6
+ gem 'rake'
7
+ gem 'rspec', '~>2'
8
+ gem 'jeweler'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,34 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ gemcutter (0.6.1)
6
+ git (1.2.5)
7
+ jeweler (1.4.0)
8
+ gemcutter (>= 0.1.0)
9
+ git (>= 1.2.5)
10
+ rubyforge (>= 2.0.0)
11
+ json_pure (1.4.6)
12
+ parallel (0.5.1)
13
+ rake (0.8.7)
14
+ rspec (2.0.1)
15
+ rspec-core (~> 2.0.1)
16
+ rspec-expectations (~> 2.0.1)
17
+ rspec-mocks (~> 2.0.1)
18
+ rspec-core (2.0.1)
19
+ rspec-expectations (2.0.1)
20
+ diff-lcs (>= 1.1.2)
21
+ rspec-mocks (2.0.1)
22
+ rspec-core (~> 2.0.1)
23
+ rspec-expectations (~> 2.0.1)
24
+ rubyforge (2.0.4)
25
+ json_pure (>= 1.1.7)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ jeweler
32
+ parallel
33
+ rake
34
+ rspec (~> 2)
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ task :default => :spec
2
+ require "rspec/core/rake_task"
3
+ RSpec::Core::RakeTask.new(:spec) do |t|
4
+ t.rspec_opts = '--backtrace --color'
5
+ end
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = "moxiesoft_parallel_tests"
11
+ gem.summary = "Run tests / specs / features in parallel"
12
+ gem.email = "grosser.michael@gmail.com"
13
+ gem.homepage = "http://github.com/edebill-moxiesoft/#{gem.name}"
14
+ gem.authors = ['Michael Grosser', 'Eric DeBill']
15
+ gem.add_dependency "parallel"
16
+ end
17
+
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
21
+ end
data/Readme.md ADDED
@@ -0,0 +1,156 @@
1
+ Speedup Test::Unit + RSpec + Cucumber by running parallel on multiple CPUs(or cores).
2
+
3
+ Setup for Rails
4
+ ===============
5
+
6
+ ## Install
7
+ ### Rails 3
8
+ As gem
9
+ sudo gem install parallel_tests
10
+ # add to Gemfile
11
+ gem "parallel_tests", :group=>:development
12
+
13
+ OR as plugin
14
+ sudo gem install parallel
15
+ rails plugin install git://github.com/grosser/parallel_tests.git
16
+
17
+ ### Rails 2
18
+
19
+ As gem
20
+ sudo gem install parallel_tests
21
+ # add to config/environments/development.rb
22
+ config.gem "parallel_tests"
23
+ # add to Rakefile
24
+ begin; require 'parallel_tests/tasks'; rescue LoadError; end
25
+
26
+ OR as plugin
27
+
28
+ sudo gem install parallel
29
+ ./script/plugin install git://github.com/grosser/parallel_tests.git
30
+
31
+ ## Setup
32
+ ### 1: Add to `config/database.yml`
33
+ test:
34
+ database: xxx_test<%= ENV['TEST_ENV_NUMBER'] %>
35
+
36
+ ### 2: Create additional database(s)
37
+ rake parallel:create
38
+
39
+ ### 3: Copy development schema (repeat after migrations)
40
+ rake parallel:prepare
41
+
42
+ ### 4: Run!
43
+ rake parallel:test # Test::Unit
44
+ rake parallel:spec # RSpec
45
+ rake parallel:features # Cucumber
46
+
47
+ rake parallel:test[1] --> force 1 CPU --> 86 seconds
48
+ rake parallel:test --> got 2 CPUs? --> 47 seconds
49
+ rake parallel:test --> got 4 CPUs? --> 26 seconds
50
+ ...
51
+
52
+ Test just a subfolder (e.g. use one integration server per subfolder)
53
+ rake parallel:test[models]
54
+ rake parallel:test[something/else]
55
+
56
+ partial paths are OK too...
57
+ rake parallel:test[functional] == rake parallel:test[fun]
58
+
59
+ Example output
60
+ --------------
61
+ 2 processes for 210 specs, ~ 105 specs per process
62
+ ... test output ...
63
+
64
+ Results:
65
+ 877 examples, 0 failures, 11 pending
66
+ 843 examples, 0 failures, 1 pending
67
+
68
+ Took 29.925333 seconds
69
+
70
+ Even process runtimes (for specs only atm)
71
+ -----------------
72
+ Add to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
73
+ --format ParallelSpecs::SpecRuntimeLogger:tmp/parallel_profile.log
74
+ It will log test runtime and partition the test-load accordingly.
75
+
76
+ Setup for non-rails
77
+ ===================
78
+ sudo gem install parallel_tests
79
+ # go to your project dir
80
+ parallel_test OR parallel_spec OR parallel_cucumber
81
+ # [Optional] use ENV['TEST_ENV_NUMBER'] inside your tests to select separate db/memcache/etc.
82
+
83
+ [optional] Only run selected files & folders:
84
+ parallel_test test/bar test/baz/xxx_text.rb
85
+
86
+ Options are:
87
+ -n [PROCESSES] How many processes to use, default: available CPUs
88
+ -p, --path [PATH] run tests inside this path only
89
+ --no-sort do not sort files before running them
90
+ -m, --multiply-processes [FLOAT] use given number as a multiplier of processes to run
91
+ -r, --root [PATH] execute test commands from this path
92
+ -e, --exec [COMMAND] execute this code parallel and with ENV['TEST_ENV_NUM']
93
+ -o, --test-options '[OPTIONS]' execute test commands with those options
94
+ -t, --type [TYPE] which type of tests to run? test, spec or features
95
+ --non-parallel execute same commands but do not in parallel, needs --exec
96
+ -v, --version Show Version
97
+ -h, --help Show this.
98
+
99
+ You can run any kind of code with -e / --execute
100
+ parallel_test -n 5 -e 'ruby -e "puts %[hello from process #{ENV[:TEST_ENV_NUMBER.to_s].inspect}]"'
101
+ hello from process "2"
102
+ hello from process ""
103
+ hello from process "3"
104
+ hello from process "5"
105
+ hello from process "4"
106
+
107
+ <table>
108
+ <tr><td></td><td>1 Process</td><td>2 Processes</td><td>4 Processes</td></tr>
109
+ <tr><td>RSpec spec-suite</td><td>18s</td><td>14s</td><td>10s</td></tr>
110
+ <tr><td>Rails-ActionPack</td><td>88s</td><td>53s</td><td>44s</td></tr>
111
+ </table>
112
+
113
+ TIPS
114
+ ====
115
+ - [Capybara + Selenium] add to env.rb: `Capybara.server_port = 8888 + ENV['TEST_ENV_NUMBER'].to_i`
116
+ - [RSpec] add a `spec/parallel_spec.opts` to use different options, e.g. no --drb (default: `spec/spec.opts`)
117
+ - [RSpec] if something looks fishy try to delete `script/spec`
118
+ - [RSpec] if `script/spec` is missing parallel:spec uses just `spec` (which solves some issues with double-loaded environment.rb)
119
+ - [RSpec] 'script/spec_server' or [spork](http://github.com/timcharper/spork/tree/master) do not work in parallel
120
+ - [RSpec] `./script/generate rspec` if you are running rspec from gems (this plugin uses script/spec which may fail if rspec files are outdated)
121
+ - [Bundler] if you have a `Gemfile` then `bundle exec` will be used to run tests
122
+ - [Capybara setup](https://github.com/grosser/parallel_tests/wiki)
123
+ - [Sphinx setup](https://github.com/grosser/parallel_tests/wiki)
124
+ - [SQL schema format] use :ruby schema format to get faster parallel:prepare`
125
+ - with zsh this would be `rake "parallel:prepare[3]"`
126
+
127
+ TODO
128
+ ====
129
+ - make jRuby compatible [basics](http://yehudakatz.com/2009/07/01/new-rails-isolation-testing/)
130
+ - make windows compatible
131
+
132
+ Authors
133
+ ====
134
+ inspired by [pivotal labs](http://pivotallabs.com/users/miked/blog/articles/849-parallelize-your-rspec-suite)
135
+
136
+ ### [Contributors](http://github.com/grosser/parallel_tests/contributors)
137
+ - [Charles Finkel](http://charlesfinkel.com/)
138
+ - [Indrek Juhkam](http://urgas.eu)
139
+ - [Jason Morrison](http://jayunit.net)
140
+ - [jinzhu](http://github.com/jinzhu)
141
+ - [Joakim Kolsjö](http://www.rubyblocks.se)
142
+ - [Kevin Scaldeferri](http://kevin.scaldeferri.com/blog/)
143
+ - [Kpumuk](http://kpumuk.info/)
144
+ - [Maksim Horbul](http://github.com/mhorbul)
145
+ - [Pivotal Labs](http://www.pivotallabs.com)
146
+ - [Rohan Deshpande](http://github.com/rdeshpande)
147
+ - [Tchandy](http://thiagopradi.net/)
148
+ - [Terence Lee](http://hone.heroku.com/)
149
+ - [Will Bryant](http://willbryant.net/)
150
+ - [Fred Wu](http://fredwu.me)
151
+ - [xxx](https://github.com/xxx)
152
+ - [Levent Ali](http://purebreeze.com/)
153
+
154
+ [Michael Grosser](http://grosser.it)<br/>
155
+ michael@grosser.it<br/>
156
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.12
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ exec "#{File.join(File.dirname(__FILE__), 'parallel_test')} -t features #{ARGV * ' '}"
data/bin/parallel_spec ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ exec "#{File.join(File.dirname(__FILE__), 'parallel_test')} -t spec #{ARGV * ' '}"
data/bin/parallel_test ADDED
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'optparse'
4
+ require 'parallel'
5
+ raise "please ' gem install parallel '" if Gem::Version.new(Parallel::VERSION) < Gem::Version.new('0.4.2')
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
7
+ require "parallel_tests"
8
+
9
+ options = {}
10
+ OptionParser.new do |opts|
11
+ opts.banner = <<BANNER
12
+ Run all tests in parallel, giving each process ENV['TEST_ENV_NUMBER'] ('', '2', '3', ...)
13
+
14
+ [optional] Only run selected files & folders:
15
+ parallel_test test/bar test/baz/xxx_text.rb
16
+
17
+ Options are:
18
+ BANNER
19
+ opts.on("-n [PROCESSES]", Integer, "How many processes to use, default: available CPUs"){|n| options[:count] = n }
20
+ opts.on("-p", '--path [PATH]', "run tests inside this path only"){|path| options[:path_prefix] = path }
21
+ opts.on("--no-sort", "do not sort files before running them"){ |no_sort| options[:no_sort] = no_sort }
22
+ opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run"){ |multiply| options[:multiply] = multiply }
23
+ opts.on("-r", '--root [PATH]', "execute test commands from this path"){|path| options[:root] = path }
24
+ opts.on("-e", '--exec [COMMAND]', "execute this code parallel and with ENV['TEST_ENV_NUM']"){|path| options[:execute] = path }
25
+ opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options"){|arg| options[:test_options] = arg }
26
+ opts.on("-t", "--type [TYPE]", "which type of tests to run? test, spec or features"){|type| options[:type] = type }
27
+ opts.on("--non-parallel", "execute same commands but do not in parallel, needs --exec"){|type| options[:non_parallel] = true }
28
+ opts.on('-v', '--version', 'Show Version'){ puts ParallelTests::VERSION; exit}
29
+ opts.on("-h", "--help", "Show this.") { puts opts; exit }
30
+ end.parse!
31
+
32
+ # get files to run from arguments
33
+ options[:files] = ARGV if ARGV.size > 0
34
+
35
+ num_processes = options[:count] || Parallel.processor_count
36
+ num_processes = num_processes * (options[:multiply] || 1)
37
+
38
+ if options[:execute]
39
+ runs = (0...num_processes).to_a
40
+ results = if options[:non_parallel]
41
+ runs.map do |i|
42
+ ParallelTests.execute_command(options[:execute], i)
43
+ end
44
+ else
45
+ Parallel.map(runs, :in_processes => num_processes) do |i|
46
+ ParallelTests.execute_command(options[:execute], i)
47
+ end
48
+ end.flatten
49
+ abort if results.any?{|r| r[:exit_status] != 0 }
50
+ else
51
+ lib, name, task = {
52
+ 'test' => ["tests", "test", "test"],
53
+ 'spec' => ["specs", "spec", "spec"],
54
+ 'features' => ["cucumber", "feature", "features"]
55
+ }[options[:type]||'test']
56
+
57
+ require "parallel_#{lib}"
58
+ klass = eval("Parallel#{lib.capitalize}")
59
+
60
+ start = Time.now
61
+
62
+ options[:path_prefix] = options[:path_prefix] ? options[:path_prefix].split(',') : ['']
63
+ tests_folder = options[:path_prefix].collect do |path|
64
+ tests_folder = File.join(task, path.to_s)
65
+ tests_folder = File.join(options[:root], tests_folder) unless options[:root].to_s.empty?
66
+ tests_folder
67
+ end
68
+ tests_folder = nil if tests_folder.empty?
69
+
70
+ puts "test folders => #{tests_folder}" if tests_folder
71
+
72
+ groups = klass.tests_in_groups(options[:files] || tests_folder, num_processes, :no_sort => options[:no_sort])
73
+ num_processes = groups.size
74
+
75
+ #adjust processes to groups
76
+ abort "no #{name}s found!" if groups.size == 0
77
+
78
+ num_tests = groups.inject(0){|sum,item| sum + item.size }
79
+ puts "#{num_processes} processes for #{num_tests} #{name}s, ~ #{num_tests / groups.size} #{name}s per process"
80
+
81
+ test_results = Parallel.map(groups, :in_processes => num_processes) do |group|
82
+ klass.run_tests(group, groups.index(group), options[:test_options])
83
+ end
84
+
85
+ #parse and print results
86
+ results = klass.find_results(test_results.map{|result| result[:stdout] }*"")
87
+ puts ""
88
+ puts "Results:"
89
+ results.each{|r| puts r }
90
+
91
+ #report total time taken
92
+ puts ""
93
+ puts "Took #{Time.now - start} seconds"
94
+
95
+ #exit with correct status code so rake parallel:test && echo 123 works
96
+ failed = test_results.any?{|result| result[:exit_status] != 0 }
97
+ abort "#{name.capitalize}s Failed" if failed
98
+ end
@@ -0,0 +1,29 @@
1
+ require File.join(File.dirname(__FILE__), 'parallel_tests')
2
+
3
+ class ParallelCucumber < ParallelTests
4
+ def self.run_tests(test_files, process_number, options)
5
+ color = ($stdout.tty? ? 'AUTOTEST=1 ; export AUTOTEST ;' : '')#display color when we are in a terminal
6
+ cmd = "#{color} #{executable} #{options} #{test_files*' '}"
7
+ execute_command(cmd, process_number)
8
+ end
9
+
10
+ def self.executable
11
+ if bundler_enabled?
12
+ "bundle exec cucumber"
13
+ elsif File.file?("script/cucumber")
14
+ "script/cucumber"
15
+ else
16
+ "cucumber"
17
+ end
18
+ end
19
+
20
+ protected
21
+
22
+ def self.test_suffix
23
+ ".feature"
24
+ end
25
+
26
+ def self.line_is_result?(line)
27
+ line =~ /^\d+ (steps|scenarios)/
28
+ end
29
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec/runner/formatter/progress_bar_formatter'
2
+
3
+ class ParallelSpecs::SpecRuntimeLogger < Spec::Runner::Formatter::BaseTextFormatter
4
+ def initialize(options, output)
5
+ if String === output
6
+ FileUtils.mkdir_p(File.dirname(output))
7
+ File.open(output,'w'){|f| f.write ''} # clean the file
8
+ @output = File.open(output, 'a+') #append so that multiple processes can write at once
9
+ else
10
+ @output = output
11
+ end
12
+ @example_times = Hash.new(0)
13
+ end
14
+
15
+ def example_started(*args)
16
+ @time = Time.now
17
+ end
18
+
19
+ def example_passed(example)
20
+ file = example.location.split(':').first
21
+ @example_times[file] += Time.now - @time
22
+ end
23
+
24
+ def start_dump(*args)
25
+ return unless ENV['TEST_ENV_NUMBER'] #only record when running in parallel
26
+ # TODO: Figure out why sometimes time can be less than 0
27
+ @output.puts @example_times.map { |file, time| "#{file}:#{time > 0 ? time : 0}" }
28
+ @output.flush
29
+ end
30
+
31
+ # stubs so that rspec doe not crash
32
+
33
+ def example_pending(*args)
34
+ end
35
+
36
+ def dump_summary(*args)
37
+ end
38
+
39
+ def dump_pending(*args)
40
+ end
41
+
42
+ def dump_failure(*args)
43
+ end
44
+
45
+ #stolen from Rspec
46
+ def close
47
+ @output.close if (IO === @output) & (@output != $stdout)
48
+ end
49
+ end
@@ -0,0 +1,48 @@
1
+ require File.join(File.dirname(__FILE__), 'parallel_tests')
2
+
3
+ class ParallelSpecs < ParallelTests
4
+ def self.run_tests(test_files, process_number, options)
5
+ exe = executable # its expensive with bundler, so do not call it twice
6
+ cmd = "#{color} #{exe} #{options} #{spec_opts(exe)} #{test_files*' '}"
7
+ execute_command(cmd, process_number)
8
+ end
9
+
10
+ def self.executable
11
+ cmd = if File.file?("script/spec")
12
+ "script/spec"
13
+ elsif bundler_enabled?
14
+ cmd = (run("bundle show rspec") =~ %r{/rspec-1[^/]+$} ? "spec" : "rspec")
15
+ "bundle exec #{cmd}"
16
+ else
17
+ %w[spec rspec].detect{|cmd| system "#{cmd} --version > /dev/null 2>&1" }
18
+ end
19
+ cmd or raise("Can't find executables rspec or spec")
20
+ end
21
+
22
+ protected
23
+
24
+ # so it can be stubbed....
25
+ def self.run(cmd)
26
+ `#{cmd}`
27
+ end
28
+
29
+ def self.spec_opts(executable)
30
+ opts = ['spec/parallel_spec.opts', 'spec/spec.opts'].detect{|f| File.file?(f) }
31
+ return unless opts
32
+ if executable =~ /\brspec\b/
33
+ # RSpec2 does not handle -O, so we inline the options
34
+ File.read(opts).tr("\n", ' ')
35
+ else
36
+ "-O #{opts}"
37
+ end
38
+ end
39
+
40
+ #display color when we are in a terminal
41
+ def self.color
42
+ ($stdout.tty? ? 'RSPEC_COLOR=1 ; export RSPEC_COLOR ;' : '')
43
+ end
44
+
45
+ def self.test_suffix
46
+ "_spec.rb"
47
+ end
48
+ end
@@ -0,0 +1,31 @@
1
+ class ParallelTests
2
+ class Grouper
3
+ def self.in_groups(items, num_groups)
4
+ [].tap do |groups|
5
+ while ! items.empty?
6
+ (0...num_groups).map do |group_number|
7
+ groups[group_number] ||= []
8
+ groups[group_number] << items.shift
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.in_even_groups_by_size(items_with_sizes, num_groups)
15
+ items_with_size = smallest_first(items_with_sizes)
16
+ groups = Array.new(num_groups){{:items => [], :size => 0}}
17
+ items_with_size.each do |item, size|
18
+ # always add to smallest group
19
+ smallest = groups.sort_by{|g| g[:size] }.first
20
+ smallest[:items] << item
21
+ smallest[:size] += size
22
+ end
23
+
24
+ groups.map{|g| g[:items] }
25
+ end
26
+
27
+ def self.smallest_first(files)
28
+ files.sort_by{|item, size| size }.reverse
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ # add rake tasks if we are inside Rails
2
+ if defined?(Rails::Railtie)
3
+ class ParallelTests
4
+ class Railtie < ::Rails::Railtie
5
+ rake_tasks do
6
+ load File.expand_path("../../tasks/parallel_tests.rake", __FILE__)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,80 @@
1
+ namespace :parallel do
2
+ def run_in_parallel(cmd, options)
3
+ count = (options[:count] ? options[:count].to_i : nil)
4
+ executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
5
+ command = "#{executable} --exec '#{cmd}' -n #{count} #{'--non-parallel' if options[:non_parallel]}"
6
+ abort unless system(command)
7
+ end
8
+
9
+ desc "create test databases via db:create --> parallel:create[num_cpus]"
10
+ task :create, :count do |t,args|
11
+ run_in_parallel('rake db:create RAILS_ENV=test', args)
12
+ end
13
+
14
+ desc "drop test databases via db:drop --> parallel:drop[num_cpus]"
15
+ task :drop, :count do |t,args|
16
+ run_in_parallel('rake db:drop RAILS_ENV=test', args)
17
+ end
18
+
19
+ desc "update test databases by dumping and loading --> parallel:prepare[num_cpus]"
20
+ task(:prepare, [:count] => 'db:abort_if_pending_migrations') do |t,args|
21
+ if ActiveRecord::Base.schema_format == :ruby
22
+ # dump then load in parallel
23
+ Rake::Task['db:schema:dump'].invoke
24
+ Rake::Task['parallel:load_schema'].invoke(args[:count])
25
+ else
26
+ # there is no separate dump / load for schema_format :sql -> do it safe and slow
27
+ args = args.to_hash.merge(:non_parallel => true) # normal merge returns nil
28
+ run_in_parallel('rake db:test:prepare --trace', args)
29
+ end
30
+ end
31
+
32
+ # when dumping/resetting takes too long
33
+ desc "update test databases via db:mgrate --> parallel:migrate[num_cpus]"
34
+ task :migrate, :count do |t,args|
35
+ run_in_parallel('rake db:migrate RAILS_ENV=test', args)
36
+ end
37
+
38
+ # just load the schema (good for integration server <-> no development db)
39
+ desc "load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
40
+ task :load_schema, :count do |t,args|
41
+ run_in_parallel('rake db:test:load', args)
42
+ end
43
+
44
+ ['test', 'spec', 'features'].each do |type|
45
+ desc "run #{type} in parallel with parallel:#{type}[num_cpus]"
46
+ task type, :count, :path_prefix, :options do |t,args|
47
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
48
+ require "parallel_tests"
49
+ count, prefix, options = ParallelTests.parse_rake_args(args)
50
+ executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
51
+ command = "#{executable} --type #{type} -n #{count} -p '#{prefix}' -r '#{Rails.root}' -o '#{options}'"
52
+ abort unless system(command) # allow to chain tasks e.g. rake parallel:spec parallel:features
53
+ end
54
+ end
55
+ end
56
+
57
+ #backwards compatability
58
+ #spec:parallel:prepare
59
+ #spec:parallel
60
+ #test:parallel
61
+ namespace :spec do
62
+ namespace :parallel do
63
+ task :prepare, :count do |t,args|
64
+ $stderr.puts "WARNING -- Deprecated! use parallel:prepare"
65
+ Rake::Task['parallel:prepare'].invoke(args[:count])
66
+ end
67
+ end
68
+
69
+ task :parallel, :count, :path_prefix do |t,args|
70
+ $stderr.puts "WARNING -- Deprecated! use parallel:spec"
71
+ Rake::Task['parallel:spec'].invoke(args[:count], args[:path_prefix])
72
+ end
73
+ end
74
+
75
+ namespace :test do
76
+ task :parallel, :count, :path_prefix do |t,args|
77
+ $stderr.puts "WARNING -- Deprecated! use parallel:test"
78
+ Rake::Task['parallel:test'].invoke(args[:count], args[:path_prefix])
79
+ end
80
+ end