lib/spork/server.rb in bmabey-spork-0.4.4 vs lib/spork/server.rb in bmabey-spork-0.5.9
- old
+ new
@@ -1,159 +1,201 @@
require 'drb/drb'
require 'rbconfig'
+require 'spork/forker.rb'
+require 'spork/custom_io_streams.rb'
+require 'spork/app_framework.rb'
-# This is based off of spec_server.rb from rspec-rails (David Chelimsky), which was based on Florian Weber's TDDMate
+# An abstract class that is implemented to create a server
+#
+# (This was originally based off of spec_server.rb from rspec-rails (David Chelimsky), which was based on Florian Weber's TDDMate)
class Spork::Server
@@supported_servers = []
LOAD_PREFERENCE = ['RSpec', 'Cucumber']
BOOTSTRAP_FILE = File.dirname(__FILE__) + "/../../assets/bootstrap.rb"
+ include Spork::CustomIOStreams
+
+ # Abstract method: returns the servers port. Override this to return the port that should be used by the test framework.
def self.port
raise NotImplemented
end
+ # Abstract method: returns the entry file that loads the testing environment, such as spec/spec_helper.rb.
def self.helper_file
raise NotImplemented
end
+ # Convenience method that turns the class name without the namespace
def self.server_name
self.name.gsub('Spork::Server::', '')
end
- def self.inherited(subclass)
- @@supported_servers << subclass
- end
-
+ # Returns a list of all testing servers that have detected their testing framework being used in the project.
def self.available_servers
supported_servers.select { |s| s.available? }
end
+ # Returns a list of all servers that have been implemented (it keeps track of them automatically via Class.inherited)
def self.supported_servers(starting_with = nil)
@@supported_servers.sort! { |a,b| a.load_preference_index <=> b.load_preference_index }
return @@supported_servers if starting_with.nil?
@@supported_servers.select do |s|
s.server_name.match(/^#{Regexp.escape(starting_with)}/i)
end
end
+ # Returns true if the testing frameworks helper file exists. Override if this is not sufficient to detect your testing framework.
def self.available?
File.exist?(helper_file)
end
+ # Used to specify
def self.load_preference_index
LOAD_PREFERENCE.index(server_name) || LOAD_PREFERENCE.length
end
- def self.using_rails?
- File.exist?("config/environment.rb")
- end
-
+ # Detects if the test helper has been bootstrapped.
def self.bootstrapped?
File.read(helper_file).include?("Spork.prefork")
end
+ # Bootstraps the current test helper file by prepending a Spork.prefork and Spork.each_run block at the beginning.
def self.bootstrap
if bootstrapped?
- puts "Already bootstrapped!"
+ stderr.puts "Already bootstrapped!"
return
end
- puts "Bootstrapping #{helper_file}."
+ stderr.puts "Bootstrapping #{helper_file}."
contents = File.read(helper_file)
bootstrap_code = File.read(BOOTSTRAP_FILE)
File.open(helper_file, "wb") do |f|
f.puts bootstrap_code
f.puts contents
end
- puts "Done. Edit #{helper_file} now with your favorite text editor and follow the instructions."
+ stderr.puts "Done. Edit #{helper_file} now with your favorite text editor and follow the instructions."
true
end
def self.run
return unless available?
new.listen
end
+ # 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.
def listen
trap("SIGINT") { sig_int_received }
trap("SIGTERM") { abort; exit!(0) }
trap("USR2") { abort; restart } if Signal.list.has_key?("USR2")
DRb.start_service("druby://127.0.0.1:#{port}", self)
- puts "Spork is ready and listening on #{port}!"
+ stderr.puts "Spork is ready and listening on #{port}!"
+ stderr.flush
DRb.thread.join
end
def port
- self.class.port
+ self.class.instance_variable_get("@port") || self.class.port
end
+
+ def self.port= p
+ @port = p
+ end
def helper_file
self.class.helper_file
end
+ # This is the public facing method that is served up by DRb. To use it from the client side (in a testing framework):
+ #
+ # DRb.start_service("druby://localhost:0") # this allows Ruby to do some magical stuff so you can pass an output stream over DRb.
+ # # see http://redmine.ruby-lang.org/issues/show/496 to see why localhost:0 is used.
+ # spec_server = DRbObject.new_with_uri("druby://127.0.0.1:8989")
+ # spec_server.run(options.argv, $stderr, $stdout)
+ #
+ # When implementing a test server, don't override this method: override run_tests instead.
def run(argv, stderr, stdout)
- return false if running?
- $stdout = stdout
- $stderr = stderr
- @child_pid = Kernel.fork do
- Spork.exec_each_run(helper_file)
+ abort if running?
+
+ @child = ::Spork::Forker.new do
+ $stdout, $stderr = stdout, stderr
+ Spork.exec_each_run { load helper_file }
run_tests(argv, stderr, stdout)
end
- Process.wait(@child_pid)
- @child_pid = nil
- true
+ @child.result
end
+ # returns whether or not the child (a test run) is running right now.
def running?
- !! @child_pid
+ @child && @child.running?
end
+ protected
+ # Abstract method: here is where the server runs the tests.
+ def run_tests(argv, input, output)
+ raise NotImplemented
+ end
+
private
+ def self.inherited(subclass)
+ @@supported_servers << subclass
+ end
+
+ def self.framework
+ @framework ||= Spork::AppFramework.detect_framework
+ end
+
+ def self.entry_point
+ bootstrapped? ? helper_file : framework.entry_point
+ end
+
def self.preload
- if bootstrapped?
- puts "Loading Spork.prefork block..."
- Spork.exec_prefork(helper_file)
- else
- puts "#{helper_file} has not been sporked. Run spork --bootstrap to do so."
- # are we in a rails app?
- if using_rails?
- puts "Preloading Rails environment"
- require "config/environment.rb"
- else
- puts "There's nothing I can really do for you. Bailing."
- return false
+ Spork.exec_prefork do
+ unless bootstrapped?
+ stderr.puts "#{helper_file} has not been bootstrapped. Run spork --bootstrap to do so."
+ stderr.flush
+
+ if framework.bootstrap_required?
+ stderr.puts "I can't do anything for you by default for the framework your using: #{framework.short_name}.\nYou must bootstrap #{helper_file} to continue."
+ stderr.flush
+ return false
+ else
+ load(framework.entry_point)
+ end
end
+
+ framework.preload do
+ if bootstrapped?
+ stderr.puts "Loading Spork.prefork block..."
+ stderr.flush
+ load(helper_file)
+ end
+ end
end
true
end
- def run_tests(argv, input, output)
- raise NotImplemented
- end
-
def restart
- puts "restarting"
+ stderr.puts "restarting"
+ stderr.flush
config = ::Config::CONFIG
ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
command_line = [ruby, $0, ARGV].flatten.join(' ')
exec(command_line)
end
def abort
- if running?
- Process.kill(Signal.list['TERM'], @child_pid)
- true
- end
+ @child && @child.abort
end
def sig_int_received
if running?
abort
- puts "Running specs stopped. Press CTRL-C again to stop the server."
+ stderr.puts "Running tests stopped. Press CTRL-C again to stop the server."
+ stderr.flush
else
exit!(0)
end
end
end
-Dir[File.dirname(__FILE__) + "/server/*.rb"].each { |file| require file }
\ No newline at end of file
+Dir[File.dirname(__FILE__) + "/server/*.rb"].each { |file| require file }