parallel_split_test 0.1.0
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/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +28 -0
- data/Rakefile +18 -0
- data/Readme.md +41 -0
- data/bin/parallel_split_test +30 -0
- data/lib/parallel_split_test.rb +2 -0
- data/lib/parallel_split_test/command_line.rb +53 -0
- data/lib/parallel_split_test/runner.rb +17 -0
- data/lib/parallel_split_test/version.rb +3 -0
- data/parallel_split_test.gemspec +15 -0
- data/spec/parallel_split_test_spec.rb +108 -0
- data/spec/spec_helper.rb +3 -0
- metadata +87 -0
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
parallel_split_test (0.1.0)
|
5
|
+
parallel (>= 0.5.12)
|
6
|
+
rspec (>= 2)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
parallel (0.5.12)
|
13
|
+
rake (0.9.2)
|
14
|
+
rspec (2.8.0)
|
15
|
+
rspec-core (~> 2.8.0)
|
16
|
+
rspec-expectations (~> 2.8.0)
|
17
|
+
rspec-mocks (~> 2.8.0)
|
18
|
+
rspec-core (2.8.0)
|
19
|
+
rspec-expectations (2.8.0)
|
20
|
+
diff-lcs (~> 1.1.2)
|
21
|
+
rspec-mocks (2.8.0)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
parallel_split_test!
|
28
|
+
rake
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
task :default do
|
4
|
+
sh "rspec spec/"
|
5
|
+
end
|
6
|
+
|
7
|
+
rule /^version:bump:.*/ do |t|
|
8
|
+
file = 'lib/parallel_split_test/version.rb'
|
9
|
+
sh "git status | grep 'nothing to commit'" # ensure we are not dirty
|
10
|
+
index = ['major', 'minor','patch'].index(t.name.split(':').last)
|
11
|
+
version_file = File.read(file)
|
12
|
+
old_version, *version_parts = version_file.match(/(\d+)\.(\d+)\.(\d+)/).to_a
|
13
|
+
version_parts[index] = version_parts[index].to_i + 1
|
14
|
+
new_version = version_parts * '.'
|
15
|
+
File.open(file,'w'){|f| f.write(version_file.sub(old_version, new_version)) }
|
16
|
+
|
17
|
+
sh "bundle && git add #{file} Gemfile.lock && git commit -m 'bump version to #{new_version}'"
|
18
|
+
end
|
data/Readme.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
Split a big test file into multiple chunks and run them in parallel
|
2
|
+
|
3
|
+
Install
|
4
|
+
=======
|
5
|
+
sudo gem install parallel_split_test
|
6
|
+
Or
|
7
|
+
|
8
|
+
rails plugin install git://github.com/grosser/parallel_split_test.git
|
9
|
+
|
10
|
+
Usage
|
11
|
+
=====
|
12
|
+
# spec/xxx_spec.rb
|
13
|
+
require "spec_helper"
|
14
|
+
|
15
|
+
describe "X" do
|
16
|
+
it {sleep 5}
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "Y" do
|
20
|
+
it {sleep 5}
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "Z" do
|
24
|
+
it {sleep 5}
|
25
|
+
end
|
26
|
+
|
27
|
+
time parallel_split_test spec/xxx_spec.rb [regular rspec options]
|
28
|
+
|
29
|
+
TODO
|
30
|
+
====
|
31
|
+
- combine exit status (1 + 0 == 1)
|
32
|
+
- support a single group with multiple sub-groups
|
33
|
+
- Test::Unit support
|
34
|
+
- Cucumber support
|
35
|
+
|
36
|
+
Author
|
37
|
+
======
|
38
|
+
[Michael Grosser](http://grosser.it)<br/>
|
39
|
+
michael@grosser.it<br/>
|
40
|
+
License: MIT<br/>
|
41
|
+
[](http://travis-ci.org/grosser/parallel_split_test)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "optparse"
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
require "parallel_split_test"
|
5
|
+
|
6
|
+
parser = OptionParser.new do |opts|
|
7
|
+
opts.banner = <<BANNER
|
8
|
+
Split a big test file into multiple chunks and run them in parallel, giving ENV['TEST_ENV_NUMBER'] ('', '2', '3', ...)
|
9
|
+
|
10
|
+
Usage:
|
11
|
+
parallel_split_test test/baz/xxx_text.rb
|
12
|
+
|
13
|
+
Options are:
|
14
|
+
BANNER
|
15
|
+
opts.on("-v", "--version", "Show Version"){ require 'parallel_split_test/version'; puts ParallelSplitTest::VERSION; exit}
|
16
|
+
opts.on("-h", "--help", "Show this.") { puts opts; exit }
|
17
|
+
end
|
18
|
+
|
19
|
+
parser.parse!
|
20
|
+
|
21
|
+
if ARGV.empty?
|
22
|
+
puts parser
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rspec"
|
27
|
+
require "parallel"
|
28
|
+
|
29
|
+
require 'parallel_split_test/runner'
|
30
|
+
ParallelSplitTest::Runner.run(ARGV)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
require 'rspec/core/command_line'
|
3
|
+
|
4
|
+
module ParallelSplitTest
|
5
|
+
class CommandLine < RSpec::Core::CommandLine
|
6
|
+
def run(err, out)
|
7
|
+
setup_copied_from_rspec(err, out)
|
8
|
+
|
9
|
+
processes = Parallel.processor_count
|
10
|
+
|
11
|
+
Parallel.in_processes(processes) do |process_number|
|
12
|
+
ENV['TEST_ENV_NUMBER'] = (process_number == 0 ? '' : (process_number + 1).to_s)
|
13
|
+
run_group_of_tests(processes, process_number)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def run_group_of_tests(processes, process_number)
|
20
|
+
example_count = @world.example_count / processes
|
21
|
+
|
22
|
+
@configuration.reporter.report(example_count, seed) do |reporter|
|
23
|
+
begin
|
24
|
+
@configuration.run_hook(:before, :suite)
|
25
|
+
groups = groups_for_this_process(@world.example_groups.ordered, process_number, processes)
|
26
|
+
groups.map {|g| g.run(reporter)}.all? ? 0 : @configuration.failure_exit_code
|
27
|
+
ensure
|
28
|
+
@configuration.run_hook(:after, :suite)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def seed
|
34
|
+
@configuration.randomize? ? @configuration.seed : nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def groups_for_this_process(groups, number, count)
|
38
|
+
selected = []
|
39
|
+
groups.each_with_index do |group, i|
|
40
|
+
selected << group if i % count == number
|
41
|
+
end
|
42
|
+
selected
|
43
|
+
end
|
44
|
+
|
45
|
+
def setup_copied_from_rspec(err, out)
|
46
|
+
@configuration.error_stream = err
|
47
|
+
@configuration.output_stream ||= out
|
48
|
+
@options.configure(@configuration)
|
49
|
+
@configuration.load_spec_files
|
50
|
+
@world.announce_filters
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rspec/core/runner'
|
2
|
+
require 'rspec/core/configuration_options'
|
3
|
+
require 'parallel_split_test/command_line'
|
4
|
+
|
5
|
+
# a cleaned up version of the RSpec runner, e.g. no drb support
|
6
|
+
module ParallelSplitTest
|
7
|
+
class Runner < RSpec::Core::Runner
|
8
|
+
def self.run(args, err=$stderr, out=$stdout)
|
9
|
+
trap_interrupt
|
10
|
+
options = RSpec::Core::ConfigurationOptions.new(args)
|
11
|
+
options.parse_options
|
12
|
+
ParallelSplitTest::CommandLine.new(options).run(err, out)
|
13
|
+
ensure
|
14
|
+
RSpec.reset
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
name = "parallel_split_test"
|
3
|
+
require "#{name}/version"
|
4
|
+
|
5
|
+
Gem::Specification.new name, ParallelSplitTest::VERSION do |s|
|
6
|
+
s.summary = "Split a big test file into multiple chunks and run them in parallel"
|
7
|
+
s.authors = ["Michael Grosser"]
|
8
|
+
s.email = "michael@grosser.it"
|
9
|
+
s.homepage = "http://github.com/grosser/#{name}"
|
10
|
+
s.files = `git ls-files`.split("\n")
|
11
|
+
s.executables = ["parallel_split_test"]
|
12
|
+
s.add_dependency "rspec", ">=2"
|
13
|
+
s.add_dependency "parallel", ">=0.5.12"
|
14
|
+
s.license = "MIT"
|
15
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ParallelSplitTest do
|
4
|
+
it "has a VERSION" do
|
5
|
+
ParallelSplitTest::VERSION.should =~ /^[\.\da-z]+$/
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "cli" do
|
9
|
+
def run(command, options={})
|
10
|
+
result = `#{command} 2>&1`
|
11
|
+
message = (options[:fail] ? "SUCCESS BUT SHOULD FAIL" : "FAIL")
|
12
|
+
raise "[#{message}] #{result} [#{command}]" if $?.success? == !!options[:fail]
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
def write(path, content)
|
17
|
+
run "mkdir -p #{File.dirname(path)}" unless File.exist?(File.dirname(path))
|
18
|
+
File.open(path, 'w'){|f| f.write content }
|
19
|
+
path
|
20
|
+
end
|
21
|
+
|
22
|
+
def parallel_split_test(x)
|
23
|
+
run "../../bin/parallel_split_test #{x}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def time
|
27
|
+
start = Time.now.to_f
|
28
|
+
yield
|
29
|
+
Time.now.to_f - start
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:root) { File.expand_path('../../', __FILE__) }
|
33
|
+
|
34
|
+
before do
|
35
|
+
run "rm -rf spec/tmp ; mkdir spec/tmp"
|
36
|
+
Dir.chdir "spec/tmp"
|
37
|
+
end
|
38
|
+
|
39
|
+
after do
|
40
|
+
Dir.chdir root
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "printing version" do
|
44
|
+
it "prints version on -v" do
|
45
|
+
parallel_split_test("-v").strip.should =~ /^[\.\da-z]+$/
|
46
|
+
end
|
47
|
+
|
48
|
+
it "prints version on --version" do
|
49
|
+
parallel_split_test("--version").strip.should =~ /^[\.\da-z]+$/
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "printing help" do
|
54
|
+
it "prints help on -h" do
|
55
|
+
parallel_split_test("-h").should include("Usage")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "prints help on --help" do
|
59
|
+
parallel_split_test("-h").should include("Usage")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "prints help on no arguments" do
|
63
|
+
parallel_split_test("").should include("Usage")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "running tests" do
|
68
|
+
it "runs in different processes" do
|
69
|
+
write "xxx_spec.rb", <<-RUBY
|
70
|
+
describe "X" do
|
71
|
+
it "a" do
|
72
|
+
puts "it-ran-a-in-\#{ENV['TEST_ENV_NUMBER'].to_i}-"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "Y" do
|
77
|
+
it "b" do
|
78
|
+
puts "it-ran-b-in-\#{ENV['TEST_ENV_NUMBER'].to_i}-"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
RUBY
|
82
|
+
result = parallel_split_test "xxx_spec.rb"
|
83
|
+
|
84
|
+
processes = ["a","b"].map do |process|
|
85
|
+
rex = /it-ran-#{process}-in-(\d)-/
|
86
|
+
result.should =~ rex
|
87
|
+
result.match(rex)[1]
|
88
|
+
end
|
89
|
+
|
90
|
+
processes.should == ['0','2']
|
91
|
+
end
|
92
|
+
|
93
|
+
it "runs faster" do
|
94
|
+
write "xxx_spec.rb", <<-RUBY
|
95
|
+
describe "X" do
|
96
|
+
it { sleep 1 }
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "Y" do
|
100
|
+
it { sleep 1 }
|
101
|
+
end
|
102
|
+
RUBY
|
103
|
+
|
104
|
+
time{ parallel_split_test "xxx_spec.rb" }.should < 2
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: parallel_split_test
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Grosser
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &84152290 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *84152290
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: parallel
|
27
|
+
requirement: &84152040 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.5.12
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *84152040
|
36
|
+
description:
|
37
|
+
email: michael@grosser.it
|
38
|
+
executables:
|
39
|
+
- parallel_split_test
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- .travis.yml
|
44
|
+
- Gemfile
|
45
|
+
- Gemfile.lock
|
46
|
+
- Rakefile
|
47
|
+
- Readme.md
|
48
|
+
- bin/parallel_split_test
|
49
|
+
- lib/parallel_split_test.rb
|
50
|
+
- lib/parallel_split_test/command_line.rb
|
51
|
+
- lib/parallel_split_test/runner.rb
|
52
|
+
- lib/parallel_split_test/version.rb
|
53
|
+
- parallel_split_test.gemspec
|
54
|
+
- spec/parallel_split_test_spec.rb
|
55
|
+
- spec/spec_helper.rb
|
56
|
+
homepage: http://github.com/grosser/parallel_split_test
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
hash: -266472017
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
hash: -266472017
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.8.10
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: Split a big test file into multiple chunks and run them in parallel
|
87
|
+
test_files: []
|