friendlyfashion-parallel_tests 0.9.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.
Files changed (41) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +8 -0
  3. data/Gemfile.lock +44 -0
  4. data/Rakefile +6 -0
  5. data/Readme.md +232 -0
  6. data/ReadmeRails2.md +48 -0
  7. data/bin/parallel_cucumber +2 -0
  8. data/bin/parallel_rspec +2 -0
  9. data/bin/parallel_test +6 -0
  10. data/lib/parallel_tests.rb +30 -0
  11. data/lib/parallel_tests/cli.rb +159 -0
  12. data/lib/parallel_tests/cucumber/gherkin_listener.rb +60 -0
  13. data/lib/parallel_tests/cucumber/runner.rb +90 -0
  14. data/lib/parallel_tests/cucumber/runtime_logger.rb +58 -0
  15. data/lib/parallel_tests/grouper.rb +53 -0
  16. data/lib/parallel_tests/railtie.rb +8 -0
  17. data/lib/parallel_tests/rspec/failures_logger.rb +44 -0
  18. data/lib/parallel_tests/rspec/logger_base.rb +52 -0
  19. data/lib/parallel_tests/rspec/runner.rb +59 -0
  20. data/lib/parallel_tests/rspec/runtime_logger.rb +34 -0
  21. data/lib/parallel_tests/rspec/summary_logger.rb +19 -0
  22. data/lib/parallel_tests/tasks.rb +134 -0
  23. data/lib/parallel_tests/test/runner.rb +134 -0
  24. data/lib/parallel_tests/test/runtime_logger.rb +92 -0
  25. data/lib/parallel_tests/version.rb +3 -0
  26. data/parallel_tests.gemspec +14 -0
  27. data/spec/integration_spec.rb +244 -0
  28. data/spec/parallel_tests/cli_spec.rb +36 -0
  29. data/spec/parallel_tests/cucumber/gherkin_listener_spec.rb +48 -0
  30. data/spec/parallel_tests/cucumber/runner_spec.rb +173 -0
  31. data/spec/parallel_tests/grouper_spec.rb +52 -0
  32. data/spec/parallel_tests/rspec/failure_logger_spec.rb +82 -0
  33. data/spec/parallel_tests/rspec/runner_spec.rb +178 -0
  34. data/spec/parallel_tests/rspec/runtime_logger_spec.rb +76 -0
  35. data/spec/parallel_tests/rspec/summary_logger_spec.rb +37 -0
  36. data/spec/parallel_tests/tasks_spec.rb +151 -0
  37. data/spec/parallel_tests/test/runner_spec.rb +273 -0
  38. data/spec/parallel_tests/test/runtime_logger_spec.rb +84 -0
  39. data/spec/parallel_tests_spec.rb +73 -0
  40. data/spec/spec_helper.rb +151 -0
  41. metadata +109 -0
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe ParallelTests::Test::RuntimeLogger do
4
+ describe :writing do
5
+ around do |example|
6
+ use_temporary_directory_for do
7
+ FileUtils.mkdir_p(File.dirname(log))
8
+ example.call
9
+ end
10
+ end
11
+
12
+ let(:log) { ParallelTests::Test::Runner.runtime_log }
13
+
14
+ it "overwrites the runtime_log file on first log invocation" do
15
+ class FakeTest
16
+ end
17
+ test = FakeTest.new
18
+ time = Time.now
19
+ File.open(log, 'w'){ |f| f.puts("FooBar") }
20
+ ParallelTests::Test::RuntimeLogger.send(:class_variable_set,:@@has_started, false)
21
+ ParallelTests::Test::RuntimeLogger.log(test, time, Time.at(time.to_f+2.00))
22
+ result = File.read(log)
23
+ result.should_not include('FooBar')
24
+ result.should include('test/fake_test.rb:2.00')
25
+ end
26
+
27
+ it "appends to the runtime_log file after first log invocation" do
28
+ class FakeTest
29
+ end
30
+ test = FakeTest.new
31
+ class OtherFakeTest
32
+ end
33
+ other_test = OtherFakeTest.new
34
+
35
+ time = Time.now
36
+ File.open(log, 'w'){ |f| f.puts("FooBar") }
37
+ ParallelTests::Test::RuntimeLogger.send(:class_variable_set,:@@has_started, false)
38
+ ParallelTests::Test::RuntimeLogger.log(test, time, Time.at(time.to_f+2.00))
39
+ ParallelTests::Test::RuntimeLogger.log(other_test, time, Time.at(time.to_f+2.00))
40
+ result = File.read(log)
41
+ result.should_not include('FooBar')
42
+ result.should include('test/fake_test.rb:2.00')
43
+ result.should include('test/other_fake_test.rb:2.00')
44
+ end
45
+ end
46
+
47
+ describe :formatting do
48
+ def call(*args)
49
+ ParallelTests::Test::RuntimeLogger.message(*args)
50
+ end
51
+
52
+ it "formats results for simple test names" do
53
+ class FakeTest
54
+ end
55
+ test = FakeTest.new
56
+ time = Time.now
57
+ call(test, time, Time.at(time.to_f+2.00)).should == 'test/fake_test.rb:2.00'
58
+ end
59
+
60
+ it "formats results for complex test names" do
61
+ class AVeryComplex
62
+ class FakeTest
63
+ end
64
+ end
65
+ test = AVeryComplex::FakeTest.new
66
+ time = Time.now
67
+ call(test, time, Time.at(time.to_f+2.00)).should == 'test/a_very_complex/fake_test.rb:2.00'
68
+ end
69
+
70
+ it "guesses subdirectory structure for rails test classes" do
71
+ module Rails
72
+ end
73
+ class ActionController
74
+ class TestCase
75
+ end
76
+ end
77
+ class FakeControllerTest < ActionController::TestCase
78
+ end
79
+ test = FakeControllerTest.new
80
+ time = Time.now
81
+ call(test, time, Time.at(time.to_f+2.00)).should == 'test/functional/fake_controller_test.rb:2.00'
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,73 @@
1
+ require "spec_helper"
2
+
3
+ describe ParallelTests do
4
+ describe ".determine_number_of_processes" do
5
+ before do
6
+ ENV.delete('PARALLEL_TEST_PROCESSORS')
7
+ Parallel.stub(:processor_count).and_return 20
8
+ end
9
+
10
+ def call(count)
11
+ ParallelTests.determine_number_of_processes(count)
12
+ end
13
+
14
+ it "uses the given count if set" do
15
+ call('5').should == 5
16
+ end
17
+
18
+ it "uses the processor count from Parallel" do
19
+ call(nil).should == 20
20
+ end
21
+
22
+ it "uses the processor count from ENV before Parallel" do
23
+ ENV['PARALLEL_TEST_PROCESSORS'] = '22'
24
+ call(nil).should == 22
25
+ end
26
+
27
+ it "does not use blank count" do
28
+ call(' ').should == 20
29
+ end
30
+
31
+ it "does not use blank env" do
32
+ ENV['PARALLEL_TEST_PROCESSORS'] = ' '
33
+ call(nil).should == 20
34
+ end
35
+ end
36
+
37
+ describe :bundler_enabled? do
38
+ before do
39
+ Object.stub!(:const_defined?).with(:Bundler).and_return false
40
+ end
41
+
42
+ it "should return false" do
43
+ use_temporary_directory_for do
44
+ ParallelTests.send(:bundler_enabled?).should == false
45
+ end
46
+ end
47
+
48
+ it "should return true when there is a constant called Bundler" do
49
+ use_temporary_directory_for do
50
+ Object.stub!(:const_defined?).with(:Bundler).and_return true
51
+ ParallelTests.send(:bundler_enabled?).should == true
52
+ end
53
+ end
54
+
55
+ it "should be true when there is a Gemfile" do
56
+ use_temporary_directory_for do
57
+ FileUtils.touch("Gemfile")
58
+ ParallelTests.send(:bundler_enabled?).should == true
59
+ end
60
+ end
61
+
62
+ it "should be true when there is a Gemfile in the parent directory" do
63
+ use_temporary_directory_for do
64
+ FileUtils.touch(File.join("..", "Gemfile"))
65
+ ParallelTests.send(:bundler_enabled?).should == true
66
+ end
67
+ end
68
+ end
69
+
70
+ it "has a version" do
71
+ ParallelTests::VERSION.should =~ /^\d+\.\d+\.\d+/
72
+ end
73
+ end
@@ -0,0 +1,151 @@
1
+ $LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
2
+
3
+ FAKE_RAILS_ROOT = './tmp/pspecs/fixtures'
4
+
5
+ require 'tempfile'
6
+ require 'parallel_tests'
7
+ require 'parallel_tests/test/runner'
8
+ require 'parallel_tests/test/runtime_logger'
9
+
10
+ require 'parallel_tests/rspec/runner'
11
+ require 'parallel_tests/rspec/runtime_logger'
12
+ require 'parallel_tests/rspec/summary_logger'
13
+
14
+ require 'parallel_tests/cucumber/runner'
15
+
16
+ OutputLogger = Struct.new(:output) do
17
+ attr_reader :flock, :flush
18
+ def puts(s=nil)
19
+ self.output << s.to_s
20
+ end
21
+ end
22
+
23
+ def mocked_process
24
+ open('|cat /dev/null')
25
+ end
26
+
27
+ def size_of(group)
28
+ group.inject(0) { |sum, test| sum += File.stat(test).size }
29
+ end
30
+
31
+ # Uses /tmp/parallel_tests/application as the cwd so we can create and remove
32
+ # files as we want to. After execution it changes cwd back to the original one.
33
+ def use_temporary_directory_for
34
+ require 'fileutils'
35
+
36
+ dir = File.join("/tmp", "parallel_tests")
37
+ new_dir = File.join(dir, "application")
38
+
39
+ begin
40
+ # just in case the temporary dir already exists
41
+ FileUtils.rm_rf(dir) if File.exists?(dir)
42
+
43
+ # create the temporary directory
44
+ FileUtils.mkdir_p(new_dir)
45
+
46
+ # chdir changes cwd back to the original one after it is done
47
+ Dir.chdir(new_dir) do
48
+ yield
49
+ end
50
+ ensure
51
+ FileUtils.rm_rf(dir) if File.exists?(dir)
52
+ end
53
+ end
54
+
55
+ def test_tests_in_groups(klass, folder, suffix)
56
+ test_root = "#{FAKE_RAILS_ROOT}/#{folder}"
57
+
58
+ describe :tests_in_groups do
59
+ before :all do
60
+ system "rm -rf #{FAKE_RAILS_ROOT}; mkdir -p #{test_root}/temp"
61
+
62
+ @files = [0,1,2,3,4,5,6,7].map do |i|
63
+ size = 99
64
+ file = "#{test_root}/temp/x#{i}#{suffix}"
65
+ File.open(file, 'w') { |f| f.puts 'x' * size }
66
+ file
67
+ end
68
+
69
+ @log = klass.runtime_log
70
+ `mkdir -p #{File.dirname(@log)}`
71
+ `rm -f #{@log}`
72
+ end
73
+
74
+ after :all do
75
+ `rm -f #{klass.runtime_log}`
76
+ end
77
+
78
+ def setup_runtime_log
79
+ File.open(@log,'w') do |f|
80
+ @files[1..-1].each{|file| f.puts "#{file}:#{@files.index(file)}"}
81
+ f.puts "#{@files[0]}:10"
82
+ end
83
+ end
84
+
85
+ it "groups when given an array of files" do
86
+ list_of_files = Dir["#{test_root}/**/*#{suffix}"]
87
+ found = klass.with_runtime_info(list_of_files)
88
+ found.should =~ list_of_files.map{ |file| [file, File.stat(file).size]}
89
+ end
90
+
91
+ it "finds all tests" do
92
+ found = klass.tests_in_groups([test_root], 1)
93
+ all = [ Dir["#{test_root}/**/*#{suffix}"] ]
94
+ (found.flatten - all.flatten).should == []
95
+ end
96
+
97
+ it "partitions them into groups by equal size" do
98
+ groups = klass.tests_in_groups([test_root], 2)
99
+ groups.map{|g| size_of(g)}.should == [400, 400]
100
+ end
101
+
102
+ it 'should partition correctly with a group size of 4' do
103
+ groups = klass.tests_in_groups([test_root], 4)
104
+ groups.map{|g| size_of(g)}.should == [200, 200, 200, 200]
105
+ end
106
+
107
+ it 'should partition correctly with an uneven group size' do
108
+ groups = klass.tests_in_groups([test_root], 3)
109
+ groups.map{|g| size_of(g)}.should =~ [300, 300, 200]
110
+ end
111
+
112
+ it "partitions by runtime when runtime-data is available" do
113
+ klass.stub!(:puts)
114
+ setup_runtime_log
115
+
116
+ groups = klass.tests_in_groups([test_root], 2)
117
+ groups.size.should == 2
118
+ # 10 + 1 + 3 + 5 = 19
119
+ groups[0].should == [@files[0],@files[1],@files[3],@files[5]]
120
+ # 2 + 4 + 6 + 7 = 19
121
+ groups[1].should == [@files[2],@files[4],@files[6],@files[7]]
122
+ end
123
+
124
+ it "alpha-sorts partitions when runtime-data is available" do
125
+ klass.stub!(:puts)
126
+ setup_runtime_log
127
+
128
+ groups = klass.tests_in_groups([test_root], 2)
129
+ groups.size.should == 2
130
+
131
+ groups[0].should == groups[0].sort
132
+ groups[1].should == groups[1].sort
133
+ end
134
+
135
+ it "partitions by round-robin when not sorting" do
136
+ files = ["file1.rb", "file2.rb", "file3.rb", "file4.rb"]
137
+ klass.should_receive(:find_tests).and_return(files)
138
+ groups = klass.tests_in_groups(files, 2, :group_by => :found).sort
139
+ groups[0].should == ["file1.rb", "file3.rb"]
140
+ groups[1].should == ["file2.rb", "file4.rb"]
141
+ end
142
+
143
+ it "alpha-sorts partitions when not sorting by runtime" do
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
+ klass.should_receive(:find_tests).and_return(files)
146
+ groups = klass.tests_in_groups(files, 2, :group_by => :found).sort
147
+ groups[0].should == groups[0].sort
148
+ groups[1].should == groups[1].sort
149
+ end
150
+ end
151
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: friendlyfashion-parallel_tests
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Laurynas Butkus
9
+ - Tomas Varaneckas
10
+ - Justas Janauskas
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2013-02-24 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: parallel
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ! '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ description:
33
+ email:
34
+ - laurynas.butkus@gmail.com
35
+ - tomas.varaneckas@gmail.com
36
+ - jjanauskas@gmail.com
37
+ executables:
38
+ - parallel_cucumber
39
+ - parallel_rspec
40
+ - parallel_test
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - Gemfile.lock
47
+ - Rakefile
48
+ - Readme.md
49
+ - ReadmeRails2.md
50
+ - bin/parallel_cucumber
51
+ - bin/parallel_rspec
52
+ - bin/parallel_test
53
+ - lib/parallel_tests.rb
54
+ - lib/parallel_tests/cli.rb
55
+ - lib/parallel_tests/cucumber/gherkin_listener.rb
56
+ - lib/parallel_tests/cucumber/runner.rb
57
+ - lib/parallel_tests/cucumber/runtime_logger.rb
58
+ - lib/parallel_tests/grouper.rb
59
+ - lib/parallel_tests/railtie.rb
60
+ - lib/parallel_tests/rspec/failures_logger.rb
61
+ - lib/parallel_tests/rspec/logger_base.rb
62
+ - lib/parallel_tests/rspec/runner.rb
63
+ - lib/parallel_tests/rspec/runtime_logger.rb
64
+ - lib/parallel_tests/rspec/summary_logger.rb
65
+ - lib/parallel_tests/tasks.rb
66
+ - lib/parallel_tests/test/runner.rb
67
+ - lib/parallel_tests/test/runtime_logger.rb
68
+ - lib/parallel_tests/version.rb
69
+ - parallel_tests.gemspec
70
+ - spec/integration_spec.rb
71
+ - spec/parallel_tests/cli_spec.rb
72
+ - spec/parallel_tests/cucumber/gherkin_listener_spec.rb
73
+ - spec/parallel_tests/cucumber/runner_spec.rb
74
+ - spec/parallel_tests/grouper_spec.rb
75
+ - spec/parallel_tests/rspec/failure_logger_spec.rb
76
+ - spec/parallel_tests/rspec/runner_spec.rb
77
+ - spec/parallel_tests/rspec/runtime_logger_spec.rb
78
+ - spec/parallel_tests/rspec/summary_logger_spec.rb
79
+ - spec/parallel_tests/tasks_spec.rb
80
+ - spec/parallel_tests/test/runner_spec.rb
81
+ - spec/parallel_tests/test/runtime_logger_spec.rb
82
+ - spec/parallel_tests_spec.rb
83
+ - spec/spec_helper.rb
84
+ homepage: http://github.com/friendlyfashion/parallel_tests
85
+ licenses:
86
+ - MIT
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 1.8.24
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Run Test::Unit / RSpec / Cucumber in parallel
109
+ test_files: []