diff options
Diffstat (limited to 'projects')
19 files changed, 709 insertions, 77 deletions
diff --git a/projects/fastthread/Rakefile b/projects/fastthread/Rakefile index c7d1269..e418a5a 100644 --- a/projects/fastthread/Rakefile +++ b/projects/fastthread/Rakefile @@ -1,48 +1,28 @@ +require 'rubygems' +gem 'echoe', '>=2.7.11' require 'echoe' Echoe.new("fastthread") do |p| p.project = "mongrel" p.author = "MenTaLguY <mental@rydia.net>" + p.email = "mental@rydia.net" p.summary = "Optimized replacement for thread.rb primitives" p.extensions = "ext/fastthread/extconf.rb" p.clean_pattern = ['build/*', '**/*.o', '**/*.so', '**/*.a', 'lib/*-*', '**/*.log', "ext/fastthread/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/fastthread/Makefile", "pkg", "lib/*.bundle", "*.gem", ".config"] p.need_tar_gz = false p.need_tgz = true - # FIXME: find a workaround to have multiple key chains outside the Rakefile - # tried GEM_CERTIFICATE_CHAIN but produces an asn1 error - p.certificate_chain = [ - '~/projects/gem_certificates/mongrel-public_cert.pem', - '~/projects/gem_certificates/luislavena-mongrel-public_cert.pem' - ] - #p.certificate_chain = ['/Users/eweaver/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem', - # '/Users/eweaver/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem'] + p.certificate_chain = ['/Users/eweaver/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem', + '/Users/eweaver/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem'] p.require_signed = true - p.eval = proc do - if RUBY_PLATFORM.match("win32") - extensions.clear - self.files += ['lib/fastthread.so'] + p.eval = proc do + if Platform.windows? self.platform = Gem::Platform::CURRENT + self.files += ['lib/fastthread.so'] task :package => [:clean, :compile] end end -end -def move_extensions - Dir["ext/**/*.#{Config::CONFIG['DLEXT']}"].each { |file| mv file, "lib/" } -end - -case RUBY_PLATFORM -when /mswin/ - filename = "lib/fastthread.so" - file filename do - Dir.chdir("ext/fastthread") do - ruby "extconf.rb" - system(PLATFORM =~ /mswin/ ? 'nmake' : 'make') - end - move_extensions - end - task :compile => [filename] end diff --git a/projects/gem_plugin/CHANGELOG b/projects/gem_plugin/CHANGELOG index 7e1103d..cf39b5b 100644 --- a/projects/gem_plugin/CHANGELOG +++ b/projects/gem_plugin/CHANGELOG @@ -1,2 +1,4 @@ +v0.3. Use Gem.path, not Gem.dir, so that local gem repositories work (rooster). + v0.2.3. Signed gem. diff --git a/projects/gem_plugin/Rakefile b/projects/gem_plugin/Rakefile index f1bd428..b312bfe 100644 --- a/projects/gem_plugin/Rakefile +++ b/projects/gem_plugin/Rakefile @@ -1,8 +1,11 @@ +require 'rubygems' +gem 'echoe', '>=2.7.11' require 'echoe' Echoe.new("gem_plugin") do |p| - p.author="Zed A. Shaw" + p.author= "Zed A. Shaw" + p.email = "mongrel-development@rubyforge.org" p.project = "mongrel" p.summary = "A plugin system based on rubygems that uses dependencies only" @@ -15,7 +18,7 @@ Echoe.new("gem_plugin") do |p| p.test_pattern = "test/test_plugins.rb" p.clean_pattern += ["pkg", "lib/*.bundle", "*.gem", ".config"] p.rdoc_pattern = ['README', 'LICENSE', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] - p.rdoc_template = `allison --path`.chomp + p.rdoc_template = `#{Platform.windows? ? 'allison.bat' : 'allison'} --path`.chomp end namespace :site do diff --git a/projects/gem_plugin/lib/gem_plugin.rb b/projects/gem_plugin/lib/gem_plugin.rb index 1996a61..782a990 100644 --- a/projects/gem_plugin/lib/gem_plugin.rb +++ b/projects/gem_plugin/lib/gem_plugin.rb @@ -105,8 +105,8 @@ module GemPlugin # To prevent this load requires the full path to the "init.rb" file, which # avoids the RubyGems autorequire magic. def load(needs = {}) - sdir = File.join(Gem.dir, "specifications") - gems = Gem::SourceIndex.from_installed_gems(sdir) + sdirs = Gem::SourceIndex.installed_spec_directories + gems = Gem::SourceIndex.from_gems_in(sdirs) needs = needs.merge({"gem_plugin" => INCLUDE}) gems.each do |path, gem| @@ -128,11 +128,17 @@ module GemPlugin # looks like no needs were set to false, so it's good # Previously was set wrong, we already have the correct gem path! - #gem_dir = File.join(Gem.dir, "gems", "#{gem.name}-#{gem.version}") - gem_dir = File.join(Gem.dir, "gems", path) + gem_dir = "" + Gem.path.each do |gem_path| + gem_dir = File.join(gem_path, "gems", path) + break if File.exist?(gem_dir) + end - require File.join(gem_dir, "lib", gem.name, "init.rb") - @gems[gem.name] = gem_dir + gem_init = File.join(gem_dir, "lib", gem.name, "init.rb") + if File.exist?(gem_init) + require gem_init + @gems[gem.name] = gem_dir + end end end diff --git a/projects/mongrel_cluster/CHANGELOG b/projects/mongrel_cluster/CHANGELOG index 6e6f31e..d860d6d 100644 --- a/projects/mongrel_cluster/CHANGELOG +++ b/projects/mongrel_cluster/CHANGELOG @@ -1,5 +1,5 @@ -v1.0.5. Close #15406 (find_pid returning non-false) (Eden Li); close #15616 (wrong Cap 2 detection) (Ryan McGeary). +v1.0.5. Close #15406 (find_pid returning non-false) (Eden Li). v1.0.4. Actually ship the Cap 2 tasks; use an autorequire based on whether namespace() is available (Kevin Runde). diff --git a/projects/mongrel_cluster/lib/mongrel_cluster/init.rb b/projects/mongrel_cluster/lib/mongrel_cluster/init.rb index 9e678d3..0f18fe9 100644 --- a/projects/mongrel_cluster/lib/mongrel_cluster/init.rb +++ b/projects/mongrel_cluster/lib/mongrel_cluster/init.rb @@ -13,7 +13,7 @@ module Cluster valid_exists?(@config_file, "Configuration file does not exist. Run mongrel_rails cluster::configure.") @valid end - + def read_options @options = { "environment" => ENV['RAILS_ENV'] || "development", @@ -59,7 +59,7 @@ module Cluster def start read_options - argv = [ "mongrel_rails" ] + argv = @options['mongrel_rails'] argv << "start" argv << "-d" argv << "-e #{@options['environment']}" if @options['environment'] @@ -80,30 +80,30 @@ module Cluster @ports.each do |port| if @clean && pid_file_exists?(port) && !check_process(port) pid_file = port_pid_file(port) - Mongrel.log("missing process: removing #{pid_file}") + log "missing process: removing #{pid_file}" chdir_cwd do File.unlink(pid_file) end end if pid_file_exists?(port) && check_process(port) - Mongrel.log("already started port #{port}") + log "already started port #{port}" next end exec_cmd = cmd + " -p #{port} -P #{port_pid_file(port)}" exec_cmd += " -l #{port_log_file(port)}" - Mongrel.log("starting port #{port}") + log "starting port #{port}" log_verbose exec_cmd output = `#{exec_cmd}` - Mongrel.log(:error, output) unless $?.success? + log_error output unless $?.success? end end def stop read_options - argv = [ "mongrel_rails" ] + argv = @options['mongrel_rails'] argv << "stop" argv << "-c #{@options["cwd"]}" if @options["cwd"] argv << "-f" if @force @@ -112,20 +112,20 @@ module Cluster @ports.each do |port| pid = check_process(port) if @clean && pid && !pid_file_exists?(port) - Mongrel.log("missing pid_file: killing mongrel_rails port #{port}, pid #{pid}") + log "missing pid_file: killing mongrel_rails port #{port}, pid #{pid}" Process.kill("KILL", pid.to_i) end if !check_process(port) - Mongrel.log("already stopped port #{port}") + log "already stopped port #{port}" next end exec_cmd = cmd + " -P #{port_pid_file(port)}" - Mongrel.log("stopping port #{port}") + log "stopping port #{port}" log_verbose exec_cmd output = `#{exec_cmd}` - Mongrel.log(:error, output) unless $?.success? + log_error output unless $?.success? end end @@ -138,18 +138,18 @@ module Cluster @ports.each do |port| pid = check_process(port) unless pid_file_exists?(port) - Mongrel.log(:error, "missing pid_file: #{port_pid_file(port)}") + log "missing pid_file: #{port_pid_file(port)}" status = STATUS_ERROR else - Mongrel.log("found pid_file: #{port_pid_file(port)}") + log "found pid_file: #{port_pid_file(port)}" end if pid - Mongrel.log("found mongrel_rails: port #{port}, pid #{pid}") + log "found mongrel_rails: port #{port}, pid #{pid}" else - Mongrel.log(:error, "missing mongrel_rails: port #{port}") + log "missing mongrel_rails: port #{port}" status = STATUS_ERROR end - Mongrel.log("") + puts "" end status @@ -211,12 +211,18 @@ module Cluster nil end + def log_error(message) + log(message) + end + def log_verbose(message) - Mongrel.log(message) if @verbose + log(message) if @verbose end + def log(message) + puts message + end end - class Start < GemPlugin::Plugin "/commands" include ExecBase @@ -294,6 +300,7 @@ module Cluster ['-C', '--config PATH', "Path to cluster configuration file", :@config_file, "config/mongrel_cluster.yml"], ['', '--user USER', "User to run as", :@user, nil], ['', '--group GROUP', "Group to run as", :@group, nil], + ['', '--mongrel_rails PATH', "Full path to mongrel_rails script", :@mongrel_rails, "mongrel_rails"], ['', '--prefix PREFIX', "Rails prefix to use", :@prefix, nil] ] end @@ -328,8 +335,9 @@ module Cluster @options["user"] = @user if @user @options["group"] = @group if @group @options["prefix"] = @prefix if @prefix + @options["mongrel_rails"] = @mongrel_rails if @mongrel_rails - Mongrel.log("Writing configuration file to #{@config_file}.") + log "Writing configuration file to #{@config_file}." File.open(@config_file,"w") {|f| f.write(@options.to_yaml)} end end diff --git a/projects/mongrel_cluster/lib/mongrel_cluster/recipes.rb b/projects/mongrel_cluster/lib/mongrel_cluster/recipes.rb index 6b62712..74ec468 100644 --- a/projects/mongrel_cluster/lib/mongrel_cluster/recipes.rb +++ b/projects/mongrel_cluster/lib/mongrel_cluster/recipes.rb @@ -1,5 +1,5 @@ -if Capistrano::Configuration.respond_to?(:instance) +if respond_to?(:namespace) require 'mongrel_cluster/recipes_2' # Cap 2 else require 'mongrel_cluster/recipes_1' # Cap 1 diff --git a/projects/mongrel_cluster/lib/mongrel_cluster/recipes_2.rb b/projects/mongrel_cluster/lib/mongrel_cluster/recipes_2.rb index a82c424..312ef5c 100644 --- a/projects/mongrel_cluster/lib/mongrel_cluster/recipes_2.rb +++ b/projects/mongrel_cluster/lib/mongrel_cluster/recipes_2.rb @@ -7,7 +7,7 @@ Capistrano::Configuration.instance.load do set :mongrel_user, nil set :mongrel_group, nil set :mongrel_prefix, nil - set :mongrel_rails, 'mongrel_rails' + set :mongrel_rails, "mongrel_rails" set :mongrel_clean, false set :mongrel_pid_file, nil set :mongrel_log_file, nil @@ -37,6 +37,7 @@ Capistrano::Configuration.instance.load do argv << "--group #{mongrel_group}" if mongrel_group argv << "--prefix #{mongrel_prefix}" if mongrel_prefix argv << "-S #{mongrel_config_script}" if mongrel_config_script + argv << "--mongrel_rails #{mongrel_rails}" if mongrel_rails cmd = argv.join " " send(run_method, cmd) end diff --git a/projects/mongrel_service/CHANGELOG b/projects/mongrel_service/CHANGELOG index 67f5086..074c87a 100644 --- a/projects/mongrel_service/CHANGELOG +++ b/projects/mongrel_service/CHANGELOG @@ -1,3 +1,8 @@ +* 0.3.5 * + + * Wait longer for child process terminate properly (max 20 seconds). Imported + tests from RubyServices project. (Closes #18). + * Updated ServiceFB to work with FB > 0.18. * 0.3.4 * diff --git a/projects/mongrel_service/Rakefile b/projects/mongrel_service/Rakefile index 1584ca3..efc9810 100644 --- a/projects/mongrel_service/Rakefile +++ b/projects/mongrel_service/Rakefile @@ -1,3 +1,6 @@ + +require 'rubygems' +gem 'echoe', '>=2.7.11' require 'echoe' require 'tools/freebasic' @@ -10,6 +13,7 @@ echoe_spec = Echoe.new("mongrel_service") do |p| p.summary += " (debug build)" unless ENV['RELEASE'] p.description = "This plugin offer native win32 services for rails, powered by Mongrel." p.author = "Luis Lavena" + p.email = "luislavena@gmail.com" p.platform = Gem::Platform::CURRENT p.dependencies = [['gem_plugin', '>=0.2.3', '<0.3.0'], ['mongrel', '>=1.0.2', '<1.2.0'], @@ -93,3 +97,42 @@ end #include_projects_of :native task :native_service => "native:build" task :clean => "native:clobber" + +project_task :mock_process do + executable :mock_process + build_to 'tests' + + main 'tests/fixtures/mock_process.bas' + + option OPTIONS +end + +task "all_tests:build" => "lib:build" +project_task :all_tests do + executable :all_tests + build_to 'tests' + + search_path 'src', 'lib', 'native' + lib_path 'lib' + + main 'tests/all_tests.bas' + + # this temporally fix the inverse namespace ctors of FB + source Dir.glob("tests/test_*.bas").reverse + + library 'testly' + + source 'native/console_process.bas' + + option OPTIONS +end + +desc "Run all the internal tests for the library" +task "all_tests:run" => ["mock_process:build", "all_tests:build"] do + Dir.chdir('tests') do + sh %{all_tests} + end +end + +desc "Run all the test for this project" +task :test => "all_tests:run" diff --git a/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas b/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas index c5150ea..c8a77a3 100644 --- a/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas +++ b/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas @@ -15,6 +15,8 @@ namespace svc namespace utils '# fb.svc.utils
'# private (internals) for ServiceProcess.Console()
dim shared _svc_stop_signal as any ptr
+ dim shared _svc_stop_mutex as any ptr
+ dim shared _svc_stopped as BOOL
dim shared _svc_in_console as ServiceProcess ptr
dim shared _svc_in_console_stop_flag as BOOL
@@ -168,6 +170,7 @@ namespace utils '# fb.svc.utils '# create the signal used to stop the service thread.
_svc_stop_signal = condcreate()
+ _svc_stop_mutex = mutexcreate()
'# register the Console Handler
SetConsoleCtrlHandler(@_console_handler, TRUE)
@@ -189,6 +192,9 @@ namespace utils '# fb.svc.utils if not (service->onStart = 0) then
'# create the thread
working_thread = threadcreate(@ServiceProcess.call_onStart, service)
+ if (working_thread = 0) then
+ print "Failed to create working thread."
+ end if
end if
print "Service is in running state."
@@ -197,7 +203,11 @@ namespace utils '# fb.svc.utils '# now that onStart is running, must monitor the stop_signal
'# in case it arrives, the service state must change to exit the
'# working thread.
- condwait(_svc_stop_signal)
+ mutexlock(_svc_stop_mutex)
+ do while (_svc_stopped = FALSE)
+ condwait(_svc_stop_signal, _svc_stop_mutex)
+ loop
+ mutexunlock(_svc_stop_mutex)
print "Stop signal received, stopping..."
@@ -222,7 +232,7 @@ namespace utils '# fb.svc.utils '# now that service was stopped, destroy the references.
conddestroy(_svc_stop_signal)
-
+ mutexdestroy(_svc_stop_mutex)
print "Done."
end if
else
@@ -287,9 +297,12 @@ namespace utils '# fb.svc.utils '# now fire the signal
_dprint("fire stop signal")
+ mutexlock(_svc_stop_mutex)
condsignal(_svc_stop_signal)
result = TRUE
_svc_in_console_stop_flag = FALSE
+ _svc_stopped = TRUE
+ mutexunlock(_svc_stop_mutex)
case else:
_dprint("unsupported CTRL EVENT")
diff --git a/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi b/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi index 67acc87..fab00f0 100644 --- a/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi +++ b/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi @@ -42,6 +42,8 @@ namespace utils '# fb.svc.utils '# will raise in case Ctrl+C / Ctrl+Break or other events are
'# received.
extern _svc_stop_signal as any ptr
+ extern _svc_stop_mutex as any ptr
+ extern _svc_stopped as BOOL
extern _svc_in_console as ServiceProcess ptr
extern _svc_in_console_stop_flag as BOOL
end namespace '# fb.svc.utils
diff --git a/projects/mongrel_service/native/console_process.bas b/projects/mongrel_service/native/console_process.bas index 78dc1a0..a2bb5c9 100644 --- a/projects/mongrel_service/native/console_process.bas +++ b/projects/mongrel_service/native/console_process.bas @@ -81,6 +81,7 @@ property ConsoleProcess.pid() as uinteger end property
property ConsoleProcess.exit_code() as uinteger
+ static previous_code as uinteger
dim result as uinteger
result = 0
@@ -90,9 +91,16 @@ property ConsoleProcess.exit_code() as uinteger if not (_process_info.hProcess = NULL) then
'# the process reference is valid, get the exit_code
if not (GetExitCodeProcess(_process_info.hProcess, @result) = 0) then
+ previous_code = result
'# OK
'# no error in the query, get result
+ if not (result = STILL_ACTIVE) then
+ CloseHandle(_process_info.hProcess)
+ _process_info.hProcess = NULL
+ end if '# (result = STILL_ACTIVE)
end if '# not (GetExitCodeProcess() = 0)
+ else
+ result = previous_code
end if '# not (proc = NULL)
end if '# not (_pid = 0)
@@ -228,7 +236,7 @@ function ConsoleProcess.start() as boolean else
'# use pipes instead
'# StdOut
- if (CreatePipe(@StdErrRd, @StdErrWr, @proc_sa, 0) = 0) then
+ if (CreatePipe(@StdErrRd, @StdErrWr, @proc_sa, 0) = 0) then
success = false
end if
@@ -283,10 +291,10 @@ function ConsoleProcess.start() as boolean CloseHandle(StdErrRd)
CloseHandle(StdErrWr)
- '# close children main Thread handle
- 'CloseHandle(proc.hThread)
- 'CloseHandle(proc.hProcess)
-
+ '# close children main Thread handle and
+ '# NULLify to avoid issues
+ CloseHandle(_process_info.hThread)
+ _process_info.hThread = NULL
end if '# (CreateProcess() = 0)
else
result = false
@@ -322,7 +330,7 @@ function ConsoleProcess.terminate(byval force as boolean = false) as boolean '# send CTRL_C_EVENT and wait for result
if not (GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0) = 0) then
'# it worked, wait 5 seconds terminates.
- wait_code = WaitForSingleObject(proc, 5000)
+ wait_code = WaitForSingleObject(proc, 10000)
if not (wait_code = WAIT_TIMEOUT) then
success = true
end if
@@ -335,7 +343,7 @@ function ConsoleProcess.terminate(byval force as boolean = false) as boolean '# send CTRL_BREAK_EVENT and wait for result
if not (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0) = 0) then
'# it worked, wait 5 seconds terminates.
- wait_code = WaitForSingleObject(proc, 5000)
+ wait_code = WaitForSingleObject(proc, 10000)
if not (wait_code = WAIT_TIMEOUT) then
success = true
end if
diff --git a/projects/mongrel_service/tests/all_tests.bas b/projects/mongrel_service/tests/all_tests.bas new file mode 100644 index 0000000..0a8864f --- /dev/null +++ b/projects/mongrel_service/tests/all_tests.bas @@ -0,0 +1,18 @@ +'#--
+'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
+'#
+'# This source code is released under the MIT License.
+'# See MIT-LICENSE file for details
+'#++
+
+#include once "testly.bi"
+
+'# the code in this module runs after all
+'# the other modules have "registered" their suites.
+
+'# evaluate the result from run_tests() to
+'# return a error to the OS or not.
+if (run_tests() = false) then
+ end 1
+end if
+
diff --git a/projects/mongrel_service/tests/fixtures/mock_process.bas b/projects/mongrel_service/tests/fixtures/mock_process.bas new file mode 100644 index 0000000..e9405ab --- /dev/null +++ b/projects/mongrel_service/tests/fixtures/mock_process.bas @@ -0,0 +1,92 @@ +'#--
+'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
+'#
+'# This source code is released under the MIT License.
+'# See MIT-LICENSE file for details
+'#++
+
+'# this program mock a common process that will:
+'# output some text to stdout
+'# output some error messages to stderr
+'# will wait until Ctrl-C is hit (only if commandline contains "wait")
+'# or drop an error if commandline contains "error"
+
+#include once "crt.bi"
+#include once "windows.bi"
+
+dim shared as any ptr control_signal, control_mutex
+dim shared flagged as byte
+dim shared result as integer
+
+function slow_console_handler(byval dwCtrlType as DWORD) as BOOL
+ dim result as BOOL
+
+ if (dwCtrlType = CTRL_C_EVENT) then
+ fprintf(stdout, !"out: CTRL-C received\r\n")
+ mutexlock(control_mutex)
+ result = 1
+ flagged = 1
+ condsignal(control_signal)
+ mutexunlock(control_mutex)
+ elseif (dwCtrlType = CTRL_BREAK_EVENT) then
+ fprintf(stdout, !"out: CTRL-BREAK received\r\n")
+ mutexlock(control_mutex)
+ result = 1
+ flagged = 2
+ condsignal(control_signal)
+ mutexunlock(control_mutex)
+ end if
+
+ return result
+end function
+
+sub wait_for(byval flag_level as integer)
+ flagged = 0
+ '# set handler
+ if (SetConsoleCtrlHandler(@slow_console_handler, 1) = 0) then
+ fprintf(stderr, !"err: cannot set console handler\r\n")
+ end if
+ fprintf(stdout, !"out: waiting for keyboard signal\r\n")
+ mutexlock(control_mutex)
+ do until (flagged = flag_level)
+ condwait(control_signal, control_mutex)
+ loop
+ mutexunlock(control_mutex)
+ fprintf(stdout, !"out: got keyboard signal\r\n")
+ if (SetConsoleCtrlHandler(@slow_console_handler, 0) = 0) then
+ fprintf(stderr, !"err: cannot unset console handler\r\n")
+ end if
+end sub
+
+function main() as integer
+ fprintf(stdout, !"out: message\r\n")
+ fprintf(stderr, !"err: error\r\n")
+
+ select case lcase(command(1))
+ case "wait":
+ sleep
+ return 0
+
+ case "error":
+ '# terminate with error code
+ return 1
+
+ case "slow1":
+ wait_for(1)
+ return 10
+
+ case "slow2":
+ wait_for(2)
+ return 20
+ end select
+end function
+
+control_signal = condcreate()
+control_mutex = mutexcreate()
+
+result = main()
+
+conddestroy(control_signal)
+mutexdestroy(control_mutex)
+
+end result
diff --git a/projects/mongrel_service/tests/test_console_process.bas b/projects/mongrel_service/tests/test_console_process.bas new file mode 100644 index 0000000..d41c0fb --- /dev/null +++ b/projects/mongrel_service/tests/test_console_process.bas @@ -0,0 +1,402 @@ +'#--
+'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
+'#
+'# This source code is released under the MIT License.
+'# See MIT-LICENSE file for details
+'#++
+
+#include once "console_process.bi"
+#include once "file.bi"
+#include once "testly.bi"
+#include once "test_helpers.bi"
+
+namespace Suite_Test_Console_Process
+ '# test helpers
+ declare function process_cleanup() as boolean
+
+ dim shared child as ConsoleProcess ptr
+
+ sub before_all()
+ kill("out.log")
+ kill("err.log")
+ kill("both.log")
+ kill("both_slow.log")
+ kill("both_forced.log")
+ end sub
+
+ sub after_each()
+ process_cleanup()
+ end sub
+
+ sub test_process_create()
+ child = new ConsoleProcess()
+ assert_not_equal(0, child)
+ assert_equal("", child->filename)
+ assert_equal("", child->arguments)
+ assert_false(child->running)
+ delete child
+ end sub
+
+ sub test_process_create_args()
+ child = new ConsoleProcess("mock_process.exe", "some params")
+ assert_equal("mock_process.exe", child->filename)
+ assert_equal("some params", child->arguments)
+ delete child
+ end sub
+
+ sub test_properly_quoted_filename()
+ child = new ConsoleProcess("C:\path with spaces\my_executable.exe", "some params")
+ assert_not_equal(0, instr(child->filename, !"\""))
+ delete child
+ end sub
+
+ sub test_failed_unexistant_process()
+ child = new ConsoleProcess("no_valid_file.exe", "some params")
+ assert_false(child->start())
+ assert_equal(0, child->pid)
+ assert_false(child->running)
+ delete child
+ end sub
+
+ sub test_process_spawn_exit_code()
+ child = new ConsoleProcess("mock_process.exe", "error")
+
+ '# start() should return true since it started, no matter if was terminated
+ '# improperly
+ assert_true(child->start())
+ sleep 500
+
+ '# should not be running, but pid should be != than 0
+ assert_not_equal(0, child->pid)
+
+ '# we need to wait a bit prior asking for state
+ '# the process could be still running
+ assert_false(child->running)
+
+ '# get exit code, should be 1
+ assert_equal(1, child->exit_code)
+
+ delete child
+ end sub
+
+ sub test_redirected_output()
+ assert_false(fileexists("out.log"))
+ assert_false(fileexists("err.log"))
+
+ '# redirected output is used with logging files.
+ child = new ConsoleProcess("mock_process.exe")
+
+ '# redirect stdout
+ assert_true(child->redirect(ProcessStdOut, "out.log"))
+ assert_string_equal("out.log", child->redirected_stdout)
+
+ '# redirect stderr
+ assert_true(child->redirect(ProcessStdErr, "err.log"))
+ assert_string_equal("err.log", child->redirected_stderr)
+
+ '# start() will be true since process terminated nicely
+ assert_true(child->start())
+ sleep 500
+
+ '# running should be false
+ assert_false(child->running)
+
+ '# exit_code should be 0
+ assert_equal(0, child->exit_code)
+
+ delete child
+
+ '# now out.log and err.log must exist and content must be valid.
+ assert_true(fileexists("out.log"))
+ assert_string_equal("out: message", content_of_file("out.log"))
+
+ assert_true(fileexists("err.log"))
+ assert_string_equal("err: error", content_of_file("err.log"))
+
+ assert_equal(0, kill("out.log"))
+ assert_equal(0, kill("err.log"))
+ end sub
+
+ sub test_redirected_merged_output()
+ dim content as string
+
+ '# redirected output is used with logging files.
+ child = new ConsoleProcess("mock_process.exe")
+
+ '# redirect both stdout and stderr
+ child->redirect(ProcessStdBoth, "both.log")
+ assert_equal("both.log", child->redirected_stdout)
+ assert_equal("both.log", child->redirected_stderr)
+
+ '# start() will be true since process terminated nicely
+ assert_true(child->start())
+ sleep 500
+
+ '# running should be false
+ assert_false(child->running)
+
+ '# exit_code should be 0
+ assert_equal(0, child->exit_code)
+
+ delete child
+
+ '# file must exists
+ assert_true(fileexists("both.log"))
+
+ '# contents must match
+ content = content_of_file("both.log")
+
+ assert_not_equal(0, instr(content, "out: message"))
+ assert_not_equal(0, instr(content, "err: error"))
+
+ assert_equal(0, kill("both.log"))
+ end sub
+
+ sub test_redirected_output_append()
+ dim content as string
+
+ child = new ConsoleProcess("mock_process.exe")
+
+ '# redirect both stdout and stderr
+ child->redirect(ProcessStdBoth, "both.log")
+
+ '# start() will be true since process terminated nicely
+ assert_true(child->start())
+ sleep 500
+
+ content = content_of_file("both.log")
+
+ '# start() again
+ assert_true(child->start())
+ sleep 500
+
+ delete child
+
+ assert_not_equal(len(content), len(content_of_file("both.log")))
+
+ assert_equal(0, kill("both.log"))
+ end sub
+
+ sub test_process_terminate()
+ dim content as string
+
+ '# redirected output is used with logging files.
+ child = new ConsoleProcess("mock_process.exe", "wait")
+ child->redirect(ProcessStdBoth, "both.log")
+
+ '# start
+ assert_true(child->start())
+ sleep 500
+
+ '# validate if running
+ assert_true(child->running)
+
+ '# validate PID
+ assert_not_equal(0, child->pid)
+
+ '# now terminates it
+ assert_true(child->terminate())
+ sleep 500
+
+ assert_equal(9, child->exit_code)
+
+ '# it should be done
+ assert_false(child->running)
+
+ delete child
+
+ '# validate output
+ '# file must exists
+ assert_true(fileexists("both.log"))
+
+ '# contents must match
+ content = content_of_file("both.log")
+
+ assert_not_equal(0, instr(content, "out: message"))
+ assert_not_equal(0, instr(content, "err: error"))
+ assert_not_equal(0, instr(content, "interrupted"))
+
+ assert_equal(0, kill("both.log"))
+ end sub
+
+ sub test_process_terminate_slow1()
+ dim content as string
+
+ '# redirected output is used with logging files.
+ child = new ConsoleProcess("mock_process.exe", "slow1")
+ child->redirect(ProcessStdBoth, "both_slow1.log")
+
+ '# start
+ assert_true(child->start())
+ sleep 500
+
+ '# validate if running
+ assert_true(child->running)
+
+ '# validate PID
+ assert_not_equal(0, child->pid)
+
+ '# now terminates it
+ assert_true(child->terminate())
+ sleep 500
+
+ assert_equal(10, child->exit_code)
+
+ '# it should be done
+ assert_false(child->running)
+
+ delete child
+
+ '# validate output
+ '# file must exists
+ assert_true(fileexists("both_slow1.log"))
+
+ '# contents must match
+ content = content_of_file("both_slow1.log")
+
+ assert_equal(0, instr(content, "interrupted"))
+ assert_not_equal(0, instr(content, "out: CTRL-C received"))
+ assert_equal(0, instr(content, "out: CTRL-BREAK received"))
+
+ assert_equal(0, kill("both_slow1.log"))
+ end sub
+
+ sub test_process_terminate_slow2()
+ dim content as string
+
+ '# redirected output is used with logging files.
+ child = new ConsoleProcess("mock_process.exe", "slow2")
+ child->redirect(ProcessStdBoth, "both_slow2.log")
+
+ '# start
+ assert_true(child->start())
+ sleep 500
+
+ '# validate if running
+ assert_true(child->running)
+
+ '# validate PID
+ assert_not_equal(0, child->pid)
+
+ '# now terminates it
+ assert_true(child->terminate())
+ sleep 500
+
+ assert_equal(20, child->exit_code)
+
+ '# it should be done
+ assert_false(child->running)
+
+ delete child
+
+ '# validate output
+ '# file must exists
+ assert_true(fileexists("both_slow2.log"))
+
+ '# contents must match
+ content = content_of_file("both_slow2.log")
+
+ assert_equal(0, instr(content, "interrupted"))
+ assert_not_equal(0, instr(content, "out: CTRL-C received"))
+ assert_not_equal(0, instr(content, "out: CTRL-BREAK received"))
+
+ '# cleanup
+ assert_equal(0, kill("both_slow2.log"))
+ end sub
+
+ sub test_process_terminate_forced()
+ dim content as string
+
+ '# redirected output is used with logging files.
+ child = new ConsoleProcess("mock_process.exe", "wait")
+ child->redirect(ProcessStdBoth, "both_forced.log")
+
+ '# start
+ assert_true(child->start())
+ sleep 500
+
+ '# validate if running
+ assert_true(child->running)
+
+ '# validate PID
+ assert_not_equal(0, child->pid)
+
+ '# now terminates it
+ assert_true(child->terminate(true))
+ sleep 500
+
+ '# it should be done
+ assert_false(child->running)
+
+ '# look for termination code
+ assert_equal(0, child->exit_code)
+
+ delete child
+
+ '# validate output
+ '# file must exists
+ assert_true(fileexists("both_forced.log"))
+
+ '# contents must match
+ content = content_of_file("both_forced.log")
+
+ assert_equal(0, instr(content, "out: message"))
+ assert_equal(0, instr(content, "err: error"))
+ assert_equal(0, instr(content, "interrupted"))
+
+ assert_equal(0, kill("both_forced.log"))
+ end sub
+
+ sub test_reuse_object_instance()
+ dim first_pid as uinteger
+
+ child = new ConsoleProcess("mock_process.exe")
+
+ '# start
+ assert_true(child->start())
+ sleep 500
+
+ '# validate not running
+ assert_false(child->running)
+
+ '# validate PID
+ assert_not_equal(0, child->pid)
+
+ '# saves PID
+ first_pid = child->pid
+
+ '# start it again
+ assert_true(child->start())
+ sleep 500
+
+ '# it should have stopped by now
+ assert_false(child->running)
+ assert_not_equal(0, child->pid)
+ assert_not_equal(first_pid, child->pid)
+
+ delete child
+ end sub
+
+ private sub register() constructor
+ add_suite(Suite_Test_Console_Process)
+ add_test(test_process_create)
+ add_test(test_process_create_args)
+ add_test(test_properly_quoted_filename)
+ add_test(test_failed_unexistant_process)
+ add_test(test_process_spawn_exit_code)
+ add_test(test_redirected_output)
+ add_test(test_redirected_merged_output)
+ add_test(test_redirected_output_append)
+ add_test(test_process_terminate)
+ add_test(test_process_terminate_slow1)
+ add_test(test_process_terminate_slow2)
+ add_test(test_process_terminate_forced)
+ add_test(test_reuse_object_instance)
+ end sub
+
+ '# test helpers below this point
+ private function process_cleanup() as boolean
+ shell "taskkill /f /im mock_process.exe 1>NUL 2>&1"
+ return true
+ end function
+end namespace
diff --git a/projects/mongrel_service/tests/test_helpers.bas b/projects/mongrel_service/tests/test_helpers.bas new file mode 100644 index 0000000..c4647c0 --- /dev/null +++ b/projects/mongrel_service/tests/test_helpers.bas @@ -0,0 +1,35 @@ +'#--
+'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
+'#
+'# This source code is released under the MIT License.
+'# See MIT-LICENSE file for details
+'#++
+
+#include once "testly.bi"
+#include once "test_helpers.bi"
+#include once "file.bi"
+
+'# Global Helpers
+function content_of_file(byref filename as string) as string
+ dim result as string
+ dim handle as integer
+ dim buffer as string
+
+ result = ""
+ buffer = ""
+
+ if (fileexists(filename) = true) then
+ handle = freefile
+ open filename for input as #handle
+ do while not (eof(handle))
+ input #handle, buffer
+ result += buffer
+ buffer = ""
+ loop
+ close #handle
+ else
+ result = ""
+ end if
+
+ return result
+end function
diff --git a/projects/mongrel_service/tests/test_helpers.bi b/projects/mongrel_service/tests/test_helpers.bi new file mode 100644 index 0000000..9397962 --- /dev/null +++ b/projects/mongrel_service/tests/test_helpers.bi @@ -0,0 +1,8 @@ +'#--
+'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems
+'#
+'# This source code is released under the MIT License.
+'# See MIT-LICENSE file for details
+'#++
+
+declare function content_of_file(byref as string) as string
\ No newline at end of file diff --git a/projects/mongrel_service/tools/freebasic.rb b/projects/mongrel_service/tools/freebasic.rb index 8902059..0b3e445 100644 --- a/projects/mongrel_service/tools/freebasic.rb +++ b/projects/mongrel_service/tools/freebasic.rb @@ -63,7 +63,7 @@ module FreeBASIC @libraries_path = []
@options = {}
- instance_eval &block
+ instance_eval(&block) if block_given?
do_cleanup
@@ -90,7 +90,7 @@ module FreeBASIC # as output_name for the project
def lib(lib_name)
@type = :lib
- @output_name = lib_name
+ @output_name = "#{lib_name}"
@real_file_name = "lib#{lib_name}.a"
end
@@ -197,7 +197,9 @@ module FreeBASIC # return the compiled name version of the passed source file (src)
# compiled_form("test.bas") => "test.o"
def compiled_form(src)
- src.ext({ ".bas" => "o", ".rc" => "obj" }[File.extname(src)])
+ unless src.nil?
+ src.ext({ ".bas" => "o", ".rc" => "obj" }[File.extname(src)])
+ end
end
def compiled_project_file
@@ -207,11 +209,11 @@ module FreeBASIC def fbc_compile(source, target, main = nil)
cmdline = []
cmdline << "fbc"
+ cmdline << "-w pedantic" if (@options.has_key?(:pedantic) && @options[:pedantic] == true)
cmdline << "-g" if (@options.has_key?(:debug) && @options[:debug] == true)
cmdline << "-#{@options[:errorchecking].to_s}" if @options.has_key?(:errorchecking)
- cmdline << "-profile" if (@options.has_key?(:profile) && @options[:profile] == true)
cmdline << "-mt" if (@options.has_key?(:mt) && @options[:mt] == true)
- cmdline << "-w pedantic" if (@options.has_key?(:pedantic) && @options[:pedantic] == true)
+ cmdline << "-profile" if (@options.has_key?(:profile) && @options[:profile] == true)
cmdline << "-c #{source}"
cmdline << "-o #{target}"
cmdline << "-m #{main}" unless main.nil?
@@ -224,8 +226,8 @@ module FreeBASIC cmdline = []
cmdline << "fbc"
cmdline << "-g" if (@options.has_key?(:debug) && @options[:debug] == true)
- cmdline << "-profile" if (@options.has_key?(:profile) && @options[:profile] == true)
cmdline << "-mt" if (@options.has_key?(:mt) && @options[:mt] == true)
+ cmdline << "-profile" if (@options.has_key?(:profile) && @options[:profile] == true)
cmdline << "-#{@type.to_s}" unless @type == :executable
cmdline << "-x #{target}"
cmdline << files << extra_files
@@ -241,11 +243,15 @@ module FreeBASIC desc "Remove all compiled files for #{@name}"
task :clobber do
# remove compiled and linked file
- rm compiled_project_file rescue nil #unless @type == :lib
- rm File.join(@build_path, @complement_file) rescue nil if @type == :dylib
+ rm compiled_project_file rescue nil if File.exist?(compiled_project_file)
+ if @type == :dylib
+ rm File.join(@build_path, @complement_file) rescue nil if File.exist?(File.join(@build_path, @complement_file))
+ end
# remove main file
- rm compiled_form(@main_file) rescue nil
+ unless @main_file.nil? || !File.exists?(compiled_form(@main_file))
+ rm compiled_form(@main_file) rescue nil
+ end
# now the sources files
# avoid attempt to remove the file two times (this is a bug in Rake)
@@ -255,7 +261,7 @@ module FreeBASIC target = compiled_form(src)
unless CLOBBER.include?(target)
CLOBBER.include(target)
- rm target rescue nil
+ rm target rescue nil if File.exist?(target)
end
end
end
|