about summary refs log tree commit homepage
path: root/projects/mongrel_service/tests
diff options
context:
space:
mode:
Diffstat (limited to 'projects/mongrel_service/tests')
-rw-r--r--projects/mongrel_service/tests/all_tests.bas18
-rw-r--r--projects/mongrel_service/tests/fixtures/mock_process.bas92
-rw-r--r--projects/mongrel_service/tests/test_console_process.bas402
-rw-r--r--projects/mongrel_service/tests/test_helpers.bas35
-rw-r--r--projects/mongrel_service/tests/test_helpers.bi8
5 files changed, 555 insertions, 0 deletions
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