parallel_tests 0.8.14 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,9 +1,8 @@
1
1
  source :rubygems
2
2
  gemspec
3
3
 
4
- group :development do
5
- gem 'test-unit', :platform => :ruby_19
6
- gem 'rspec', '>=2.4'
7
- gem 'cucumber'
8
- gem 'rake'
9
- end
4
+ gem 'bump'
5
+ gem 'test-unit', :platform => :ruby_19
6
+ gem 'rspec', '>=2.4'
7
+ gem 'cucumber'
8
+ gem 'rake'
@@ -1,33 +1,34 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- parallel_tests (0.8.14)
4
+ parallel_tests (0.9.0)
5
5
  parallel
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
9
9
  specs:
10
10
  builder (3.0.0)
11
+ bump (0.3.8)
11
12
  cucumber (1.1.4)
12
13
  builder (>= 2.1.2)
13
14
  diff-lcs (>= 1.1.2)
14
15
  gherkin (~> 2.7.1)
15
16
  json (>= 1.4.6)
16
17
  term-ansicolor (>= 1.0.6)
17
- diff-lcs (1.1.2)
18
+ diff-lcs (1.1.3)
18
19
  gherkin (2.7.6)
19
20
  json (>= 1.4.6)
20
- json (1.6.4)
21
- parallel (0.5.18)
22
- rake (0.8.7)
23
- rspec (2.6.0)
24
- rspec-core (~> 2.6.0)
25
- rspec-expectations (~> 2.6.0)
26
- rspec-mocks (~> 2.6.0)
27
- rspec-core (2.6.4)
28
- rspec-expectations (2.6.0)
29
- diff-lcs (~> 1.1.2)
30
- rspec-mocks (2.6.0)
21
+ json (1.7.5)
22
+ parallel (0.6.1)
23
+ rake (10.0.3)
24
+ rspec (2.12.0)
25
+ rspec-core (~> 2.12.0)
26
+ rspec-expectations (~> 2.12.0)
27
+ rspec-mocks (~> 2.12.0)
28
+ rspec-core (2.12.2)
29
+ rspec-expectations (2.12.1)
30
+ diff-lcs (~> 1.1.3)
31
+ rspec-mocks (2.12.1)
31
32
  term-ansicolor (1.0.7)
32
33
  test-unit (2.4.4)
33
34
 
@@ -35,6 +36,7 @@ PLATFORMS
35
36
  ruby
36
37
 
37
38
  DEPENDENCIES
39
+ bump
38
40
  cucumber
39
41
  parallel_tests!
40
42
  rake
data/Rakefile CHANGED
@@ -1,22 +1,6 @@
1
+ require 'bump/tasks'
1
2
  require 'bundler/gem_tasks'
2
3
 
3
4
  task :default do
4
5
  sh "rspec spec/"
5
6
  end
6
-
7
- # extracted from https://github.com/grosser/project_template
8
- rule /^version:bump:.*/ do |t|
9
- sh "git status | grep 'nothing to commit'" # ensure we are not dirty
10
- index = ['major', 'minor','patch'].index(t.name.split(':').last)
11
- file = 'lib/parallel_tests/version.rb'
12
-
13
- version_file = File.read(file)
14
- old_version, *version_parts = version_file.match(/(\d+)\.(\d+)\.(\d+)/).to_a
15
- version_parts[index] = version_parts[index].to_i + 1
16
- version_parts[2] = 0 if index < 2 # remove patch for minor
17
- version_parts[1] = 0 if index < 1 # remove minor for major
18
- new_version = version_parts * '.'
19
- File.open(file,'w'){|f| f.write(version_file.sub(old_version, new_version)) }
20
-
21
- sh "bundle && git add #{file} Gemfile.lock && git commit -m 'bump version to #{new_version}'"
22
- end
data/Readme.md CHANGED
@@ -132,7 +132,8 @@ Options are:
132
132
  steps - number of cucumber steps
133
133
  default - runtime or filesize
134
134
  -m, --multiply-processes [FLOAT] use given number as a multiplier of processes to run
135
- -s, --single [PATTERN] Run all matching files in only one process
135
+ -s, --single [PATTERN] Run all matching files in the same process
136
+ -i, --isolate Do not run any other tests in the group used by --single(-s)
136
137
  -e, --exec [COMMAND] execute this code parallel and with ENV['TEST_ENV_NUM']
137
138
  -o, --test-options '[OPTIONS]' execute test commands with those options
138
139
  -t, --type [TYPE] test(default) / rspec / cucumber
@@ -176,6 +177,7 @@ TIPS
176
177
 
177
178
  TODO
178
179
  ====
180
+ - fix tests vs cucumber >= 1.2 `unknown option --format`
179
181
  - add tests for the rake tasks, maybe generate a rails project ...
180
182
  - add unit tests for cucumber runtime formatter
181
183
  - make jRuby compatible [basics](http://yehudakatz.com/2009/07/01/new-rails-isolation-testing/)
@@ -222,6 +224,8 @@ inspired by [pivotal labs](http://pivotallabs.com/users/miked/blog/articles/849-
222
224
  - [Ulrich Berkmüller](https://github.com/ulrich-berkmueller)
223
225
  - [Grzegorz Derebecki](https://github.com/madmax)
224
226
  - [Florian Motlik](https://github.com/flomotlik)
227
+ - [Artem Kuzko](https://github.com/akuzko)
228
+ - [Zeke Fast](https://github.com/zekefast)
225
229
 
226
230
  [Michael Grosser](http://grosser.it)<br/>
227
231
  michael@grosser.it<br/>
@@ -25,13 +25,13 @@ module ParallelTest
25
25
 
26
26
  report_time_taken do
27
27
  groups = runner.tests_in_groups(options[:files], num_processes, options)
28
- report_number_of_tests runner, groups
28
+ report_number_of_tests(runner, groups)
29
29
 
30
30
  test_results = Parallel.map(groups, :in_processes => groups.size) do |group|
31
31
  run_tests(runner, group, groups.index(group), options)
32
32
  end
33
33
 
34
- report_results runner, test_results
34
+ report_results(runner, test_results)
35
35
  end
36
36
 
37
37
  abort final_fail_message(lib) if any_test_failed?(test_results)
@@ -89,10 +89,20 @@ group tests by:
89
89
  TEXT
90
90
  ) { |type| options[:group_by] = type.to_sym }
91
91
  opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run") { |multiply| options[:multiply] = multiply }
92
- opts.on("-s [PATTERN]", "--single [PATTERN]", "Run all matching files in only one process") do |pattern|
92
+
93
+ opts.on("-s [PATTERN]", "--single [PATTERN]",
94
+ "Run all matching files in the same process") do |pattern|
95
+
93
96
  options[:single_process] ||= []
94
97
  options[:single_process] << /#{pattern}/
95
98
  end
99
+
100
+ opts.on("-i", "--isolate",
101
+ "Do not run any other tests in the group used by --single(-s)") do |pattern|
102
+
103
+ options[:isolate] = true
104
+ end
105
+
96
106
  opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUM']") { |path| options[:execute] = path }
97
107
  opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg }
98
108
  opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber") { |type| options[:type] = type }
@@ -131,13 +141,13 @@ TEXT
131
141
  def self.report_time_taken
132
142
  start = Time.now
133
143
  yield
134
- puts ""
135
- puts "Took #{Time.now - start} seconds"
144
+ puts "\nTook #{Time.now - start} seconds"
136
145
  end
137
146
 
138
147
  def self.final_fail_message(lib)
139
148
  fail_message = "#{lib.capitalize}s Failed"
140
149
  fail_message = "\e[31m#{fail_message}\e[0m" if use_colors?
150
+
141
151
  fail_message
142
152
  end
143
153
 
@@ -1,32 +1,19 @@
1
1
  module ParallelTests
2
2
  class Grouper
3
- def self.in_groups(items, num_groups)
4
- groups = Array.new(num_groups){ [] }
5
-
6
- until items.empty?
7
- num_groups.times do |group_number|
8
- if item = items.shift
9
- groups[group_number] << item
10
- end
11
- end
12
- end
13
-
14
- groups.map!(&:sort!)
15
- end
16
-
17
- def self.in_even_groups_by_size(items_with_sizes, num_groups, options={})
18
- groups = Array.new(num_groups){{:items => [], :size => 0}}
3
+ def self.in_even_groups_by_size(items_with_sizes, num_groups, options = {})
4
+ groups = Array.new(num_groups) { {:items => [], :size => 0} }
19
5
 
20
6
  # add all files that should run in a single process to one group
21
- (options[:single_process]||[]).each do |pattern|
22
- matched, items_with_sizes = items_with_sizes.partition{|item, size| item =~ pattern }
23
- smallest = smallest_group(groups)
24
- matched.each{|item,size| add_to_group(smallest, item, size) }
7
+ (options[:single_process] || []).each do |pattern|
8
+ matched, items_with_sizes = items_with_sizes.partition { |item, size| item =~ pattern }
9
+ matched.each { |item, size| add_to_group(groups.first, item, size) }
25
10
  end
26
11
 
12
+ groups_to_fill = (options[:isolate] ? groups[1..-1] : groups)
13
+
27
14
  # add all other files
28
15
  largest_first(items_with_sizes).each do |item, size|
29
- smallest = smallest_group(groups)
16
+ smallest = smallest_group(groups_to_fill)
30
17
  add_to_group(smallest, item, size)
31
18
  end
32
19
 
@@ -108,18 +108,25 @@ namespace :parallel do
108
108
 
109
109
  ['test', 'spec', 'features'].each do |type|
110
110
  desc "run #{type} in parallel with parallel:#{type}[num_cpus]"
111
- task type, [:count, :pattern, :options] do |t,args|
111
+ task type, [:count, :pattern, :options] do |t, args|
112
112
  ParallelTests::Tasks.check_for_pending_migrations
113
+
113
114
  $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
114
115
  require "parallel_tests"
116
+
115
117
  count, pattern, options = ParallelTests::Tasks.parse_args(args)
116
118
  test_framework = {
117
119
  'spec' => 'rspec',
118
120
  'test' => 'test',
119
121
  'features' => 'cucumber'
120
122
  }[type]
123
+
121
124
  executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
122
- command = "#{executable} #{type} --type #{test_framework} -n #{count} -p '#{pattern}' -o '#{options}'"
125
+ command = "#{executable} #{type} --type #{test_framework} " \
126
+ "-n #{count} " \
127
+ "--pattern '#{pattern}' " \
128
+ "--test-options '#{options}'"
129
+
123
130
  abort unless system(command) # allow to chain tasks e.g. rake parallel:spec parallel:features
124
131
  end
125
132
  end
@@ -31,12 +31,12 @@ module ParallelTests
31
31
  def self.tests_in_groups(tests, num_groups, options={})
32
32
  tests = find_tests(tests, options)
33
33
 
34
- if options[:group_by] == :found
35
- Grouper.in_groups(tests, num_groups)
34
+ tests = if options[:group_by] == :found
35
+ tests.map { |t| [t, 1] }
36
36
  else
37
- tests = with_runtime_info(tests)
38
- Grouper.in_even_groups_by_size(tests, num_groups, options)
37
+ with_runtime_info(tests)
39
38
  end
39
+ Grouper.in_even_groups_by_size(tests, num_groups, options)
40
40
  end
41
41
 
42
42
  def self.execute_command(cmd, process_number, options)
@@ -73,10 +73,11 @@ module ParallelTests
73
73
  sum[word] += number.to_i
74
74
  sum
75
75
  end
76
+
76
77
  sums
77
78
  end
78
79
 
79
- # read output of the process and print in in chucks
80
+ # read output of the process and print it in chunks
80
81
  def self.fetch_output(process)
81
82
  all = ''
82
83
  while buffer = process.readpartial(1000000)
@@ -84,6 +85,7 @@ module ParallelTests
84
85
  $stdout.print buffer
85
86
  $stdout.flush
86
87
  end rescue EOFError
88
+
87
89
  all
88
90
  end
89
91
 
@@ -105,8 +107,8 @@ module ParallelTests
105
107
  end
106
108
  end
107
109
 
108
- def self.find_tests(tests, options={})
109
- (tests||[]).map do |file_or_folder|
110
+ def self.find_tests(tests, options = {})
111
+ (tests || []).map do |file_or_folder|
110
112
  if File.directory?(file_or_folder)
111
113
  files = files_in_folder(file_or_folder, options)
112
114
  files.grep(/#{Regexp.escape test_suffix}$/).grep(options[:pattern]||//)
@@ -1,3 +1,3 @@
1
1
  module ParallelTests
2
- VERSION = Version = '0.8.14'
2
+ VERSION = Version = '0.9.0'
3
3
  end
@@ -49,14 +49,4 @@ describe ParallelTests::Grouper do
49
49
  call(6).should == [["5"], ["4"], ["3"], ["2"], ["1"], []]
50
50
  end
51
51
  end
52
-
53
- describe :in_groups do
54
- it "groups" do
55
- ParallelTests::Grouper.in_groups([1,2,3],2).should == [[1,3],[2]]
56
- end
57
-
58
- it "keeps groups sorted" do
59
- ParallelTests::Grouper.in_groups([3,2,1],2).should == [[1,3],[2]]
60
- end
61
- end
62
52
  end
@@ -24,7 +24,7 @@ describe ParallelTests::RSpec::SummaryLogger do
24
24
  logger.dump_failures
25
25
  output.output.should == []
26
26
  logger.dump_summary(1,2,3,4)
27
- output.output.map{|o| decolorize(o) }.should == ["\nFinished in 1 seconds\n", "2 examples, 3 failures, 4 pending"]
27
+ output.output.map{|o| decolorize(o) }.should == ["\nFinished in 1 second\n", "2 examples, 3 failures, 4 pending"]
28
28
  end
29
29
 
30
30
  it "does not print anything for pending examples" do
@@ -32,6 +32,6 @@ describe ParallelTests::RSpec::SummaryLogger do
32
32
  logger.dump_failures
33
33
  output.output.should == []
34
34
  logger.dump_summary(1,2,3,4)
35
- output.output.map{|o| decolorize(o) }.should == ["\nFinished in 1 seconds\n", "2 examples, 3 failures, 4 pending"]
35
+ output.output.map{|o| decolorize(o) }.should == ["\nFinished in 1 second\n", "2 examples, 3 failures, 4 pending"]
36
36
  end
37
37
  end
@@ -5,7 +5,7 @@ describe ParallelTests::Tasks do
5
5
  describe ".parse_args" do
6
6
  it "should return the count" do
7
7
  args = {:count => 2}
8
- ParallelTests::Tasks.parse_args(args).should == [2, '', ""]
8
+ ParallelTests::Tasks.parse_args(args).should == [2, "", ""]
9
9
  end
10
10
 
11
11
  it "should default to the prefix" do
@@ -19,7 +19,7 @@ describe ParallelTests::Tasks do
19
19
  end
20
20
 
21
21
  it "should return the count, pattern, and options" do
22
- args = {:count => 2, :pattern => "plain", :options => "-p default" }
22
+ args = {:count => 2, :pattern => "plain", :options => "-p default"}
23
23
  ParallelTests::Tasks.parse_args(args).should == [2, "plain", "-p default"]
24
24
  end
25
25
  end
@@ -38,20 +38,41 @@ describe ParallelTests::Test::Runner do
38
38
 
39
39
  it "does not sort when passed false do_sort option" do
40
40
  ParallelTests::Test::Runner.should_not_receive(:smallest_first)
41
- call [], 1, :group_by => :found
41
+ call([], 1, :group_by => :found)
42
42
  end
43
43
 
44
44
  it "does sort when not passed do_sort option" do
45
45
  ParallelTests::Test::Runner.stub!(:tests_with_runtime).and_return([])
46
46
  ParallelTests::Grouper.should_receive(:largest_first).and_return([])
47
- call [], 1
47
+ call([], 1)
48
48
  end
49
49
 
50
50
  it "groups by single_process pattern and then via size" do
51
- ParallelTests::Test::Runner.should_receive(:with_runtime_info).and_return([['aaa',5],['aaa2',5],['bbb',2],['ccc',1],['ddd',1]])
52
- result = call [], 3, :single_process => [/^a.a/]
51
+ ParallelTests::Test::Runner.should_receive(:with_runtime_info).
52
+ and_return([
53
+ ['aaa', 5],
54
+ ['aaa2', 5],
55
+ ['bbb', 2],
56
+ ['ccc', 1],
57
+ ['ddd', 1]
58
+ ])
59
+ result = call([], 3, :single_process => [/^a.a/])
53
60
  result.should == [["aaa", "aaa2"], ["bbb"], ["ccc", "ddd"]]
54
61
  end
62
+
63
+ it "groups by size and adds isolated separately" do
64
+ ParallelTests::Test::Runner.should_receive(:with_runtime_info).
65
+ and_return([
66
+ ['aaa', 0],
67
+ ['bbb', 3],
68
+ ['ccc', 1],
69
+ ['ddd', 2],
70
+ ['eee', 1]
71
+ ])
72
+
73
+ result = call([], 3, :isolate => true, :single_process => [/^aaa/])
74
+ result.should == [["aaa"], ["bbb", "eee"], ["ccc", "ddd"]]
75
+ end
55
76
  end
56
77
 
57
78
  describe :find_results do
@@ -135,7 +135,7 @@ def test_tests_in_groups(klass, folder, suffix)
135
135
  it "partitions by round-robin when not sorting" do
136
136
  files = ["file1.rb", "file2.rb", "file3.rb", "file4.rb"]
137
137
  klass.should_receive(:find_tests).and_return(files)
138
- groups = klass.tests_in_groups(files, 2, :group_by => :found)
138
+ groups = klass.tests_in_groups(files, 2, :group_by => :found).sort
139
139
  groups[0].should == ["file1.rb", "file3.rb"]
140
140
  groups[1].should == ["file2.rb", "file4.rb"]
141
141
  end
@@ -143,7 +143,7 @@ def test_tests_in_groups(klass, folder, suffix)
143
143
  it "alpha-sorts partitions when not sorting by runtime" do
144
144
  files = %w[q w e r t y u i o p a s d f g h j k l z x c v b n m]
145
145
  klass.should_receive(:find_tests).and_return(files)
146
- groups = klass.tests_in_groups(files, 2, :group_by => :found)
146
+ groups = klass.tests_in_groups(files, 2, :group_by => :found).sort
147
147
  groups[0].should == groups[0].sort
148
148
  groups[1].should == groups[1].sort
149
149
  end
metadata CHANGED
@@ -1,32 +1,32 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel_tests
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.14
5
4
  prerelease:
5
+ version: 0.9.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Michael Grosser
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-18 00:00:00.000000000 Z
12
+ date: 2012-12-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: parallel
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
15
+ version_requirements: !ruby/object:Gem::Requirement
18
16
  requirements:
19
17
  - - ! '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
20
  none: false
21
+ prerelease: false
22
+ name: parallel
23
+ requirement: !ruby/object:Gem::Requirement
26
24
  requirements:
27
25
  - - ! '>='
28
26
  - !ruby/object:Gem::Version
29
27
  version: '0'
28
+ none: false
29
+ type: :runtime
30
30
  description:
31
31
  email: michael@grosser.it
32
32
  executables:
@@ -84,23 +84,23 @@ rdoc_options: []
84
84
  require_paths:
85
85
  - lib
86
86
  required_ruby_version: !ruby/object:Gem::Requirement
87
- none: false
88
87
  requirements:
89
88
  - - ! '>='
90
89
  - !ruby/object:Gem::Version
91
90
  version: '0'
92
91
  segments:
93
92
  - 0
94
- hash: 1255476358488583165
95
- required_rubygems_version: !ruby/object:Gem::Requirement
93
+ hash: -4090660521181020432
96
94
  none: false
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
96
  requirements:
98
97
  - - ! '>='
99
98
  - !ruby/object:Gem::Version
100
99
  version: '0'
101
100
  segments:
102
101
  - 0
103
- hash: 1255476358488583165
102
+ hash: -4090660521181020432
103
+ none: false
104
104
  requirements: []
105
105
  rubyforge_project:
106
106
  rubygems_version: 1.8.24