nimboids-spork 0.8.99

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 (59) hide show
  1. data/Gemfile +6 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +129 -0
  4. data/assets/bootstrap.rb +29 -0
  5. data/bin/spork +20 -0
  6. data/ext/mkrf_conf.rb +26 -0
  7. data/features/at_exit_during_each_run.feature +36 -0
  8. data/features/cucumber_rails_integration.feature +107 -0
  9. data/features/diagnostic_mode.feature +41 -0
  10. data/features/gemfiles/rails3.0/Gemfile +10 -0
  11. data/features/gemfiles/rails3.0/Gemfile.lock +116 -0
  12. data/features/rails_delayed_loading_workarounds.feature +150 -0
  13. data/features/rspec_rails_integration.feature +92 -0
  14. data/features/spork_debugger.feature +108 -0
  15. data/features/steps/general_steps.rb +3 -0
  16. data/features/steps/rails_steps.rb +67 -0
  17. data/features/steps/sandbox_steps.rb +115 -0
  18. data/features/support/background_job.rb +63 -0
  19. data/features/support/bundler_helpers.rb +41 -0
  20. data/features/support/env.rb +105 -0
  21. data/features/unknown_app_framework.feature +42 -0
  22. data/lib/spork.rb +155 -0
  23. data/lib/spork/app_framework.rb +80 -0
  24. data/lib/spork/app_framework/padrino.rb +22 -0
  25. data/lib/spork/app_framework/rails.rb +82 -0
  26. data/lib/spork/app_framework/unknown.rb +6 -0
  27. data/lib/spork/custom_io_streams.rb +25 -0
  28. data/lib/spork/diagnoser.rb +105 -0
  29. data/lib/spork/ext/rails-reloader.rb +14 -0
  30. data/lib/spork/ext/ruby-debug.rb +150 -0
  31. data/lib/spork/forker.rb +71 -0
  32. data/lib/spork/run_strategy.rb +44 -0
  33. data/lib/spork/run_strategy/forking.rb +32 -0
  34. data/lib/spork/run_strategy/magazine.rb +141 -0
  35. data/lib/spork/run_strategy/magazine/magazine_slave.rb +30 -0
  36. data/lib/spork/run_strategy/magazine/magazine_slave_provider.rb +27 -0
  37. data/lib/spork/run_strategy/magazine/ring_server.rb +10 -0
  38. data/lib/spork/runner.rb +90 -0
  39. data/lib/spork/server.rb +76 -0
  40. data/lib/spork/test_framework.rb +167 -0
  41. data/lib/spork/test_framework/cucumber.rb +24 -0
  42. data/lib/spork/test_framework/rspec.rb +14 -0
  43. data/spec/spec_helper.rb +113 -0
  44. data/spec/spork/app_framework/rails_spec.rb +22 -0
  45. data/spec/spork/app_framework/unknown_spec.rb +12 -0
  46. data/spec/spork/app_framework_spec.rb +16 -0
  47. data/spec/spork/diagnoser_spec.rb +105 -0
  48. data/spec/spork/forker_spec.rb +44 -0
  49. data/spec/spork/run_strategy/forking_spec.rb +38 -0
  50. data/spec/spork/runner_spec.rb +50 -0
  51. data/spec/spork/server_spec.rb +15 -0
  52. data/spec/spork/test_framework/cucumber_spec.rb +11 -0
  53. data/spec/spork/test_framework/rspec_spec.rb +10 -0
  54. data/spec/spork/test_framework_shared_examples.rb +23 -0
  55. data/spec/spork/test_framework_spec.rb +90 -0
  56. data/spec/spork_spec.rb +153 -0
  57. data/spec/support/fake_framework.rb +15 -0
  58. data/spec/support/fake_run_strategy.rb +21 -0
  59. metadata +158 -0
@@ -0,0 +1,44 @@
1
+ class Spork::RunStrategy
2
+ attr_reader :test_framework
3
+ @@run_strategies = []
4
+
5
+ def initialize(test_framework)
6
+ @test_framework = test_framework
7
+ end
8
+
9
+ def preload
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def run(argv, input, output)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def cleanup
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def running?
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def abort
26
+ raise NotImplementedError
27
+ end
28
+
29
+ protected
30
+ def self.factory(test_framework)
31
+ if RUBY_PLATFORM =~ /mswin|mingw|java/
32
+ Spork::RunStrategy::Magazine.new(test_framework)
33
+ else
34
+ Spork::RunStrategy::Forking.new(test_framework)
35
+ end
36
+ end
37
+
38
+ def self.inherited(subclass)
39
+ @@run_strategies << subclass
40
+ end
41
+
42
+ end
43
+
44
+ Dir[File.dirname(__FILE__) + "/run_strategy/*.rb"].each { |file| require file }
@@ -0,0 +1,32 @@
1
+ class Spork::RunStrategy::Forking < Spork::RunStrategy
2
+ def self.available?
3
+ Kernel.respond_to?(:fork)
4
+ end
5
+
6
+ def run(argv, stderr, stdout)
7
+ abort if running?
8
+
9
+ @child = ::Spork::Forker.new do
10
+ $stdout, $stderr = stdout, stderr
11
+ load test_framework.helper_file
12
+ Spork.exec_each_run
13
+ result = test_framework.run_tests(argv, stderr, stdout)
14
+ Spork.exec_after_each_run
15
+ result
16
+ end
17
+ @child.result
18
+ end
19
+
20
+ def abort
21
+ @child && @child.abort
22
+ end
23
+
24
+ def preload
25
+ test_framework.preload
26
+ end
27
+
28
+ def running?
29
+ @child && @child.running?
30
+ end
31
+
32
+ end
@@ -0,0 +1,141 @@
1
+ # this class' goal:
2
+ # to boldly just run test after test
3
+ # as they come in
4
+ require 'drb'
5
+ require 'rinda/ring'
6
+ require 'win32/process' if RUBY_PLATFORM =~ /mswin|mingw/ and RUBY_VERSION < '1.9.1'
7
+ require 'rubygems' # used for Gem.ruby
8
+
9
+ $:.unshift(File.dirname(__FILE__))
10
+ require 'magazine/magazine_slave'
11
+
12
+ class Spork::RunStrategy::Magazine < Spork::RunStrategy
13
+
14
+ Slave_Id_Range = 1..2 # Ringserver uses id: 0. Slave use: 1..MAX_SLAVES
15
+
16
+ def slave_max
17
+ Slave_Id_Range.to_a.size
18
+ end
19
+
20
+ def initialize(test_framework)
21
+ @test_framework = test_framework
22
+ this_path = File.expand_path(File.dirname(__FILE__))
23
+ @path = File.join(this_path, 'magazine')
24
+ @pids = []
25
+
26
+ @pids << start_Rinda_ringserver
27
+ sleep 1
28
+
29
+ fill_slave_pool
30
+ rescue RuntimeError => e
31
+ kill_all_processes
32
+ raise e
33
+ end
34
+
35
+ def start_Rinda_ringserver
36
+ app_name = "#{Gem.ruby} ring_server.rb"
37
+ spawn_process(app_name)
38
+ end
39
+
40
+ def fill_slave_pool
41
+ Slave_Id_Range.each do |id|
42
+ start_slave(id)
43
+ end
44
+ puts " -- Starting to fill pool..."
45
+ puts " Wait until at least one slave is provided before running tests..."
46
+ puts " ** CTRL+BREAK to stop Spork and kill all ruby slave processes **"
47
+ $stdout.flush
48
+ end
49
+
50
+ def start_slave(id)
51
+ app_pwd = Dir.pwd # path running app in
52
+ app = "#{Gem.ruby} magazine_slave_provider.rb #{id} '#{app_pwd}' #{@test_framework.short_name}"
53
+ @pids[id] = spawn_process(app)
54
+ end
55
+
56
+ def spawn_process(app)
57
+
58
+ if RUBY_PLATFORM =~ /java/
59
+ # jruby 1.8 has no easy way to just spawn, so use a thread
60
+ Dir.chdir(@path) do
61
+ io = IO.popen app
62
+ Thread.new { puts io.read }
63
+ return io.pid
64
+ end
65
+ end
66
+
67
+ if RUBY_VERSION < '1.9.1'
68
+ Process.create( :app_name => app, :cwd => @path ).process_id
69
+ else
70
+ Process.spawn( app, :chdir => @path )
71
+ end
72
+ end
73
+
74
+ def self.available?
75
+ true
76
+ end
77
+
78
+ def run(argv, stderr, stdout)
79
+ DRb.start_service
80
+ ts = Rinda::RingFinger.primary
81
+ if ts.read_all([:name, :MagazineSlave, nil, nil]).size > 0
82
+ print ' <-- take tuple'; stdout.flush
83
+ tuple = ts.take([:name, :MagazineSlave, nil, nil])
84
+ slave = tuple[2]
85
+ id = tuple[3]
86
+
87
+ puts "(#{slave.id_num}); slave.run..."; $stdout.flush
88
+ begin
89
+ slave.run(argv,stderr,stdout)
90
+ puts " -- (#{slave.id_num});run done"; $stdout.flush
91
+ ensure
92
+ restart_slave(id)
93
+ end
94
+ else
95
+ puts '- NO tuple'; $stdout.flush
96
+ end
97
+ end
98
+
99
+ def restart_slave(id)
100
+ pid = @pids[id]
101
+ Process.kill(9, pid)
102
+ start_slave(id)
103
+ end
104
+
105
+ def windows?
106
+ ENV['OS'] == 'Windows_NT'
107
+ end
108
+
109
+ def kill_all_processes
110
+
111
+ @pids.each {|pid|
112
+ if windows?
113
+ system("taskkill /f /pid #{pid}")
114
+ else
115
+ Process.kill(9, pid)
116
+ end
117
+ }
118
+ puts "\nKilling processes."; $stdout.flush
119
+ end
120
+
121
+ def slave_count
122
+ DRb.start_service
123
+ ts = Rinda::RingFinger.primary
124
+ ts.read_all([:name, :MagazineSlave, nil, nil]).size
125
+ end
126
+
127
+
128
+ def abort
129
+ kill_all_processes
130
+ end
131
+
132
+ def preload
133
+ true
134
+ # @test_framework.preload
135
+ end
136
+
137
+ def running?
138
+ @running
139
+ end
140
+
141
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'drb'
3
+ $:.unshift(File.dirname(__FILE__) + "/../../..") # directory of spork.rb
4
+ require 'spork'
5
+
6
+ class MagazineSlave
7
+ include DRb::DRbUndumped
8
+ attr_reader :id_num
9
+ def initialize(id_num, test_framework_short_name)
10
+ @id_num = id_num
11
+ @test_framework = Spork::TestFramework.factory(STDOUT, STDERR,
12
+ test_framework_short_name)
13
+ # ENV["DRB"] = 'true'
14
+ # Spork.using_spork!
15
+ return(nil) unless preload
16
+ end
17
+
18
+ def run(argv, stderr, stdout)
19
+ $stdout, $stderr = stdout, stderr
20
+ Spork.exec_each_run
21
+ load @test_framework.helper_file
22
+ @test_framework.run_tests(argv, stderr, stdout)
23
+ puts " <-- Slave(#{@id_num}) run done!"; stdout.flush
24
+ end
25
+
26
+ def preload
27
+ @test_framework.preload
28
+ end
29
+
30
+ end
@@ -0,0 +1,27 @@
1
+ # magazine_slave_provider.rb
2
+ require 'drb'
3
+ require 'rinda/ring'
4
+ require 'rinda/tuplespace'
5
+ require 'magazine_slave'
6
+
7
+
8
+
9
+ # pass on
10
+
11
+ id = ARGV[0].to_i || "?"
12
+ app_pwd = ARGV[1]
13
+ test_framework_short_name = ARGV[2]
14
+
15
+ # start up the Rinda service
16
+
17
+ DRb.start_service
18
+
19
+ Dir.chdir app_pwd
20
+ puts " -- build slave #{id}..."; $stdout.flush
21
+ magazine_slave = MagazineSlave.new(id, test_framework_short_name )
22
+ Rinda::RingProvider.new(:MagazineSlave, magazine_slave, id).provide
23
+
24
+ puts " --> DRb magazine_slave_service: #{id} provided..."; $stdout.flush
25
+
26
+ # wait for the DRb service to finish before exiting
27
+ DRb.thread.join
@@ -0,0 +1,10 @@
1
+ # ring_server.rb
2
+ require 'rinda/ring'
3
+ require 'rinda/tuplespace'
4
+
5
+ DRb.start_service
6
+
7
+ Rinda::RingServer.new(Rinda::TupleSpace.new)
8
+ puts " -- Rinda Ring Server listening for connections...\n\n"
9
+ $stdout.flush
10
+ DRb.thread.join
@@ -0,0 +1,90 @@
1
+ require 'optparse'
2
+ require 'stringio'
3
+
4
+ module Spork
5
+ # This is used by bin/spork. It's wrapped in a class because it's easier to test that way.
6
+ class Runner
7
+ attr_reader :test_framework
8
+
9
+ def self.run(args, output, error)
10
+ self.new(args, output, error).run
11
+ end
12
+
13
+ def initialize(args, output, error)
14
+ raise ArgumentError, "expected array of args" unless args.is_a?(Array)
15
+ @output = output
16
+ @error = error
17
+ @options = {}
18
+ opt = OptionParser.new
19
+ opt.banner = "Usage: spork [test framework name] [options]\n\n"
20
+
21
+ opt.separator "Options:"
22
+ opt.on("-b", "--bootstrap") {|ignore| @options[:bootstrap] = true }
23
+ opt.on("-d", "--diagnose") {|ignore| @options[:diagnose] = true }
24
+ opt.on("-h", "--help") {|ignore| @options[:help] = true }
25
+ opt.on("-p", "--port [PORT]") {|port| @options[:port] = port }
26
+ non_option_args = args.select { |arg| ! args[0].match(/^-/) }
27
+ @options[:server_matcher] = non_option_args[0]
28
+ opt.parse!(args)
29
+
30
+ if @options[:help]
31
+ @output.puts opt
32
+ @output.puts
33
+ @output.puts supported_test_frameworks_text
34
+ exit(0)
35
+ end
36
+ end
37
+
38
+ def supported_test_frameworks_text
39
+ text = StringIO.new
40
+
41
+ text.puts "Supported test frameworks:"
42
+ text.puts Spork::TestFramework.supported_test_frameworks.sort { |a,b| a.short_name <=> b.short_name }.map { |s| (s.available? ? '(*) ' : '( ) ') + s.short_name }
43
+ text.puts "\nLegend: ( ) - not detected in project (*) - detected\n"
44
+ text.string
45
+ end
46
+
47
+ # Returns a server for the specified (or the detected default) testing framework. Returns nil if none detected, or if the specified is not supported or available.
48
+ def find_test_framework
49
+ Spork::TestFramework.factory(@output, @error, options[:server_matcher])
50
+ rescue Spork::TestFramework::NoFrameworksAvailable => e
51
+ @error.puts e.message
52
+ rescue Spork::TestFramework::FactoryException => e
53
+ @error.puts "#{e.message}\n\n#{supported_test_frameworks_text}"
54
+ end
55
+
56
+ def run
57
+ return false unless test_framework = find_test_framework
58
+ ENV["DRB"] = 'true'
59
+ @error.puts "Using #{test_framework.short_name}"
60
+ @error.flush
61
+
62
+ case
63
+ when options[:bootstrap]
64
+ test_framework.bootstrap
65
+ when options[:diagnose]
66
+ require 'spork/diagnoser'
67
+
68
+ Spork::Diagnoser.install_hook!(test_framework.entry_point)
69
+ test_framework.preload
70
+ Spork::Diagnoser.output_results(@output)
71
+ return true
72
+ else
73
+ run_strategy = Spork::RunStrategy.factory(test_framework)
74
+ return(false) unless run_strategy.preload
75
+ Spork::Server.run(:port => @options[:port] || test_framework.default_port, :run_strategy => run_strategy)
76
+ return true
77
+ end
78
+ end
79
+
80
+ private
81
+ attr_reader :options
82
+
83
+ end
84
+ end
85
+
86
+
87
+
88
+
89
+
90
+
@@ -0,0 +1,76 @@
1
+ require 'drb/drb'
2
+ require 'rbconfig'
3
+ require 'spork/forker.rb'
4
+ require 'spork/custom_io_streams.rb'
5
+ require 'spork/app_framework.rb'
6
+
7
+ # An abstract class that is implemented to create a server
8
+ #
9
+ # (This was originally based off of spec_server.rb from rspec-rails (David Chelimsky), which was based on Florian Weber's TDDMate)
10
+ class Spork::Server
11
+ attr_reader :run_strategy
12
+ include Spork::CustomIOStreams
13
+
14
+ def initialize(options = {})
15
+ @run_strategy = options[:run_strategy]
16
+ @port = options[:port]
17
+ end
18
+
19
+ def self.run(options = {})
20
+ new(options).listen
21
+ end
22
+
23
+ # Sets up signals and starts the DRb service. If it's successful, it doesn't return. Not ever. You don't need to override this.
24
+ def listen
25
+ raise RuntimeError, "you must call Spork.using_spork! before starting the server" unless Spork.using_spork?
26
+ trap("SIGINT") { sig_int_received }
27
+ trap("SIGTERM") { abort; exit!(0) }
28
+ trap("USR2") { abort; restart } if Signal.list.has_key?("USR2")
29
+ @drb_service = DRb.start_service("druby://127.0.0.1:#{port}", self)
30
+ Spork.each_run { @drb_service.stop_service } if @run_strategy.class == Spork::RunStrategy::Forking
31
+ stderr.puts "Spork is ready and listening on #{port}!"
32
+ stderr.flush
33
+ DRb.thread.join
34
+ end
35
+
36
+ attr_accessor :port
37
+
38
+ # This is the public facing method that is served up by DRb. To use it from the client side (in a testing framework):
39
+ #
40
+ # DRb.start_service("druby://localhost:0") # this allows Ruby to do some magical stuff so you can pass an output stream over DRb.
41
+ # # see http://redmine.ruby-lang.org/issues/show/496 to see why localhost:0 is used.
42
+ # spec_server = DRbObject.new_with_uri("druby://127.0.0.1:8989")
43
+ # spec_server.run(options.argv, $stderr, $stdout)
44
+ #
45
+ # When implementing a test server, don't override this method: override run_tests instead.
46
+ def run(argv, stderr, stdout)
47
+ puts "Running tests with args #{argv.inspect}..."
48
+ run_strategy.run(argv, stderr, stdout)
49
+ puts "Done.\n\n"
50
+ end
51
+
52
+ def abort
53
+ run_strategy.abort
54
+ end
55
+
56
+ private
57
+ def restart
58
+ stderr.puts "restarting"
59
+ stderr.flush
60
+ config = ::Config::CONFIG
61
+ ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
62
+ command_line = [ruby, $0, ARGV].flatten.join(' ')
63
+ exec(command_line)
64
+ end
65
+
66
+ def sig_int_received
67
+ stdout.puts "\n"
68
+ if run_strategy.running?
69
+ abort
70
+ stderr.puts "Running tests stopped. Press CTRL-C again to stop the server."
71
+ stderr.flush
72
+ else
73
+ exit!(0)
74
+ end
75
+ end
76
+ end