ngauthier-multitest 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  coverage
4
4
  rdoc
5
5
  pkg
6
+ tmp
@@ -2,45 +2,76 @@
2
2
 
3
3
  == Caveats
4
4
 
5
- Multitest currently is not really tested and working with databases all that well. I have a project in Postgres with all of my data done transactionally during the test via factory_girl. It works there. But it didn't work on a quick test in a MySQL project.
6
-
7
5
  Multitest is still very young, it is in active development and is no where near complete or robust.
8
6
 
7
+ Multitest currently only works in a rails environment. It's only because I use "constantize".
8
+
9
+ If you depend on fixture data in your database, you may have data inconsistency errors. I like to use an empty DB and then use factories with transactional tests, and this runs great.
10
+
9
11
  == Installation
10
12
 
11
- gem install ngauthier-multitest
13
+ gem install ngauthier-multitest
12
14
 
13
15
  == Usage
14
16
 
15
17
  in your Rakefile:
16
18
 
17
- require 'multitest'
18
- require 'multitest/tasks'
19
+ require 'multitest'
20
+ require 'multitest/tasks'
19
21
 
20
22
  on the commandline:
21
23
 
22
- rake multitest
23
- rake multitest:units multitest:functionals multitest:integration
24
+ rake multitest
25
+ rake multitest:units multitest:functionals multitest:integration
24
26
 
25
27
  == Configuration
26
28
 
27
29
  in your Rakefile:
28
30
 
29
- Multitest.cores = 8
31
+ Multitest.cores = 8
32
+
33
+ == Benchmarks
34
+
35
+ This is one of our largest apps.
36
+
37
+ === Normal suite
38
+
39
+ time rake test
40
+ 259.03user 27.50system 5:14.76elapsed 91%CPU
41
+
42
+ === 2 Cores
43
+
44
+ time rake multitest
45
+ 213.86user 23.38system 2:41.24elapsed 147%CPU
46
+
47
+ === 4 Cores
48
+
49
+ time rake multitest
50
+ 223.18user 24.53system 2:08.96elapsed 192%CPU
51
+
52
+ Note the wall-time differences of 5:14 vs 2:41. 195% speedup on two cores. On 4 cores there is only a speedup of 243%, but that's still quicker. If you send me impressive benchmarks, I'll be happy to put them up here (8 cores anyone?).
53
+
54
+ == Require Errors
55
+
56
+ If you get require errors like:
30
57
 
31
- == Examples
58
+ Running multitest:units
59
+ rake aborted!
60
+ no such file to load -- test_helper
32
61
 
33
- On a small app that I have:
62
+ Then you may want to use more absolute paths in your tests. For example, if you had:
34
63
 
35
- Normal suite
36
- time rake test
37
- 16.38user 2.99system 0:20.38elapsed 95%CPU
64
+ # test/unit/my_class.rb
65
+ require 'test_helper'
66
+ class MyClass < ActiveSupport::TestCase
67
+ end
38
68
 
39
- 2 Cores:
40
- time rake multitest
41
- 8.35user 1.64system 0:08.51elapsed 117%CPU
69
+ You should change it to:
42
70
 
43
- Note the wall-time differences of 20.38 vs 8.51. 239% speedup on two cores.
71
+ # test/unit/my_class.rb
72
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
73
+ class MyClass < ActiveSupport::TestCase
74
+ end
44
75
 
45
76
  == Note on Patches/Pull Requests
46
77
 
@@ -50,7 +81,7 @@ Note the wall-time differences of 20.38 vs 8.51. 239% speedup on two cores.
50
81
  future version unintentionally.
51
82
  * Commit, do not mess with rakefile, version, or history.
52
83
  (if you want to have your own version, that is fine but
53
- bump version in a commit by itself I can ignore when I pull)
84
+ bump version in a commit by itself I can ignore when I pull)
54
85
  * Send me a pull request. Bonus points for topic branches.
55
86
 
56
87
  == Copyright
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -1,4 +1,5 @@
1
1
  require File.join(File.dirname(__FILE__), 'pipe_dream')
2
+ require File.join(File.dirname(__FILE__), 'safe_fork')
2
3
  require 'test/unit/testresult'
3
4
  require 'test/unit'
4
5
 
@@ -32,39 +33,27 @@ class Multitest
32
33
  $stderr.write @files.inspect+"\n"; $stderr.flush
33
34
  @cores.times do |c|
34
35
  @pipes << PipeDream.new
35
- @children << Process.fork do
36
+ @children << SafeFork.fork do
36
37
  Signal.trap("TERM") { exit }
37
38
  Signal.trap("HUP") { exit }
38
39
  pipe = @pipes.last
39
40
  pipe.identify_as_child
40
41
  pipe.write("[Worker #{c}] Booted\n")
42
+ @result = Test::Unit::TestResult.new
43
+ @result.add_listener(Test::Unit::TestResult::FAULT) do |value|
44
+ $stderr.write value
45
+ $stderr.write "\n\n"
46
+ $stderr.flush
47
+ end
41
48
  while !pipe.eof?
42
49
  file = pipe.gets.chomp
43
50
  begin
44
51
  pipe.write "[Worker #{c} Starting: #{file}\n"
45
52
  start = Time.now
46
53
 
47
- @result = Test::Unit::TestResult.new
48
- @result.add_listener(Test::Unit::TestResult::FAULT) do |value|
49
- # $stderr.write "\n"
50
- $stderr.write value
51
- $stderr.write "\n\n"
52
- $stderr.flush
53
- end
54
54
  klasses = Multitest.find_classes_in_file(file)
55
55
  klasses.each{|k| k.suite.run(@result){|status, name| ;}}
56
56
 
57
- #puts @result
58
-
59
- #unless @result[:failures].empty?
60
- # puts @result[:failures].inspect
61
- #end
62
-
63
- #unless @result.errors.empty?
64
- # puts @result.errors.inspect
65
- #end
66
-
67
-
68
57
  finish = Time.now
69
58
  pipe.write "[Worker #{c}] Completed: #{file} (#{finish-start})\n"
70
59
  rescue => ex
@@ -119,8 +108,22 @@ class Multitest
119
108
  def self.find_classes_in_file(f)
120
109
  code = ""
121
110
  File.open(f) {|buffer| code = buffer.read}
122
- matches = code.scan /class\s+([\S]+)/
123
- klasses = matches.collect{|c| eval(c.first) }
111
+ matches = code.scan(/class\s+([\S]+)/)
112
+ klasses = matches.collect do |c|
113
+ begin
114
+ if c.first.respond_to? :constantize
115
+ c.first.constantize
116
+ else
117
+ eval(c.first)
118
+ end
119
+ rescue NameError
120
+ # $stderr.write "Could not load [#{c.first}] from [#{f}]\n"
121
+ nil
122
+ rescue SyntaxError
123
+ # $stderr.write "Could not load [#{c.first}] from [#{f}]\n"
124
+ nil
125
+ end
126
+ end
124
127
  return klasses.select{|k| k.respond_to? 'suite'}
125
128
  end
126
129
 
@@ -0,0 +1,24 @@
1
+ class SafeFork
2
+ def self.fork
3
+ begin
4
+ # remove our connection so it doesn't get cloned
5
+ ActiveRecord::Base.remove_connection if defined?(ActiveRecord)
6
+ # fork a process
7
+ child = Process.fork do
8
+ begin
9
+ # create a new connection and perform the action
10
+ ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
11
+ yield
12
+ ensure
13
+ # make sure we remove the connection before we're done
14
+ ActiveRecord::Base.remove_connection if defined?(ActiveRecord)
15
+ end
16
+ end
17
+ ensure
18
+ # make sure we re-establish the connection before returning to the main instance
19
+ ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
20
+ end
21
+ return child
22
+ end
23
+ end
24
+
@@ -4,7 +4,7 @@ module Multitest::Tasks
4
4
 
5
5
  namespace :multitest do
6
6
  desc "Multi-core test:units"
7
- task :units do
7
+ task :units => [:environment] do
8
8
  pattern = 'test/unit/**/*_test.rb'
9
9
  files = Dir.glob(pattern)
10
10
  $stderr.write "Running multitest:units\n"
@@ -12,7 +12,7 @@ module Multitest::Tasks
12
12
  $stderr.write "Completed multitest:units\n\n"
13
13
  end
14
14
  desc "Multi-core test:functionals"
15
- task :functionals do
15
+ task :functionals => [:environment] do
16
16
  pattern = 'test/functional/**/*_test.rb'
17
17
  files = Dir.glob(pattern)
18
18
  $stderr.write "Running multitest:functionals\n"
@@ -20,7 +20,7 @@ module Multitest::Tasks
20
20
  $stderr.write "Completed multitest:functionals\n\n"
21
21
  end
22
22
  desc "Multi-core test:integration"
23
- task :integration do
23
+ task :integration => [:environment] do
24
24
  pattern = 'test/integration/**/*_test.rb'
25
25
  files = Dir.glob(pattern)
26
26
  $stderr.write "Running multitest:integration\n"
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{multitest}
8
- s.version = "0.1.0"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nick Gauthier"]
12
- s.date = %q{2009-09-24}
12
+ s.date = %q{2009-09-25}
13
13
  s.description = %q{Run your tests across multiple cores automatically.}
14
14
  s.email = %q{nick@smartlogicsolutions.com}
15
15
  s.extra_rdoc_files = [
@@ -29,6 +29,8 @@ Gem::Specification.new do |s|
29
29
  "lib/multitest/multitest.rb",
30
30
  "lib/multitest/pipe_dream.rb",
31
31
  "lib/multitest/pipe_dream.rb",
32
+ "lib/multitest/safe_fork.rb",
33
+ "lib/multitest/safe_fork.rb",
32
34
  "lib/multitest/tasks.rb",
33
35
  "lib/multitest/tasks.rb",
34
36
  "multitest.gemspec",
@@ -4,12 +4,12 @@ require 'multitest'
4
4
  class MultitestTest < Test::Unit::TestCase
5
5
  context "a Multitest" do
6
6
  setup do
7
+ FileUtils.mkdir_p(File.join(File.dirname(__FILE__), '..', 'tmp'))
8
+ FileUtils.rm_rf(File.expand_path(File.join(File.dirname(__FILE__), '..', 'tmp', 'test.log')))
7
9
  @mt = Multitest.new([
8
10
  File.expand_path(File.join(File.dirname(__FILE__), 'tests', 'sample_test.rb')),
9
11
  File.expand_path(File.join(File.dirname(__FILE__), 'tests', 'another_test.rb'))
10
12
  ])
11
- FileUtils.mkdir_p(File.join(File.dirname(__FILE__), '..', 'tmp'))
12
- FileUtils.rm_rf(File.expand_path(File.join(File.dirname(__FILE__), '..', 'tmp', 'test.log')))
13
13
  end
14
14
 
15
15
  should "run three instances" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ngauthier-multitest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Gauthier
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-24 00:00:00 -07:00
12
+ date: 2009-09-25 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -41,6 +41,7 @@ files:
41
41
  - lib/multitest.rb
42
42
  - lib/multitest/multitest.rb
43
43
  - lib/multitest/pipe_dream.rb
44
+ - lib/multitest/safe_fork.rb
44
45
  - lib/multitest/tasks.rb
45
46
  - multitest.gemspec
46
47
  - test/multitest_test.rb