Revision: 3094
Author: jussi.ao.malinen
Date: Mon Apr 26 06:26:12 2010
Log: Implemented stopping test execution gracefully with ctrl-c, issue 108
http://code.google.com/p/robotframework/source/detail?r=3094

Added:
 /trunk/src/robot/utils/signalhandler.py
Modified:
 /trunk/src/robot/__init__.py
 /trunk/src/robot/running/handlers.py

=======================================
--- /dev/null
+++ /trunk/src/robot/utils/signalhandler.py     Mon Apr 26 06:26:12 2010
@@ -0,0 +1,55 @@
+#  Copyright 2008-2009 Nokia Siemens Networks Oyj
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import signal
+import sys
+
+from robot.errors import ExecutionFailed
+
+
+class _RobotSignalHandler(object):
+
+    def __init__(self):
+        self._signal_count = 0
+        self._running_keyword = False
+
+    def __call__(self,signum, frame):
+        self._signal_count += 1
+        if self._signal_count > 1:
+            sys.__stderr__.write("Execution forcefully stopped.")
+            raise SystemExit()
+ sys.__stderr__.write("Stopping execution. Second signal will force exit.")
+        if self._running_keyword:
+            self._stop_execution_gracefully()
+
+    def _stop_execution_gracefully(self):
+        raise ExecutionFailed("Execution terminated by signal", exit=True)
+
+    def start(self):
+        signal.signal(signal.SIGINT, self)
+        signal.signal(signal.SIGTERM, self)
+
+    def start_running_keyword(self):
+        self._running_keyword = True
+        if self._signal_count:
+            self._stop_execution_gracefully()
+
+    def stop_running_keyword(self):
+        self._running_keyword = False
+
+    def is_break_signaled(self):
+        return self.count > 0
+
+
+ROBOT_SIGNAL_HANDLER = _RobotSignalHandler()
=======================================
--- /trunk/src/robot/__init__.py        Tue Mar  2 02:57:25 2010
+++ /trunk/src/robot/__init__.py        Mon Apr 26 06:26:12 2010
@@ -12,7 +12,6 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.

-
 import sys

 if __name__ == '__main__':
@@ -29,6 +28,7 @@
         DATA_ERROR, STOPPED_BY_USER, FRAMEWORK_ERROR
 from variables import init_global_variables
 import utils
+from utils.signalhandler import ROBOT_SIGNAL_HANDLER

 __version__ = utils.version

@@ -91,6 +91,7 @@
     pybot /path/to/tests.html
     pybot --log mylog.html /path/to/tests.html /path/to/tests2.html
     """
+    ROBOT_SIGNAL_HANDLER.start()
     settings = RobotSettings(options)
     LOGGER.register_console_logger(settings['MonitorWidth'],
                                    settings['MonitorColors'])
=======================================
--- /trunk/src/robot/running/handlers.py        Tue Apr 20 06:46:51 2010
+++ /trunk/src/robot/running/handlers.py        Mon Apr 26 06:26:12 2010
@@ -20,6 +20,7 @@
 from arguments import PythonKeywordArguments, JavaKeywordArguments, \
     DynamicKeywordArguments, PythonInitArguments, JavaInitArguments, \
     RunKeywordArguments
+from robot.utils.signalhandler import ROBOT_SIGNAL_HANDLER


 if utils.is_jython:
@@ -92,10 +93,22 @@
         return self._run_handler_with_output_captured(runner, output)

     def _runner_for(self, handler, output, positional, named, timeout):
+        wrapped_handler = self._wrap_with_signal_handling(handler)
         if timeout and timeout.active():
- return lambda: timeout.run(handler, args=positional, kwargs=named, + return lambda: timeout.run(wrapped_handler, args=positional, kwargs=named,
                                        logger=output)
-        return lambda: handler(*positional, **named)
+        return lambda: wrapped_handler(*positional, **named)
+
+    def _wrap_with_signal_handling(self, runnable):
+        def _signal_wrapper(runnable):
+            def _wrapped_function(*wrapped_positional, **wrapped_named):
+                try:
+                    ROBOT_SIGNAL_HANDLER.start_running_keyword()
+                    return runnable(*wrapped_positional, **wrapped_named)
+                finally:
+                    ROBOT_SIGNAL_HANDLER.stop_running_keyword()
+            return _wrapped_function
+        return _signal_wrapper(runnable)

     def _run_handler_with_output_captured(self, runner, output):
         utils.capture_output()
@@ -178,6 +191,9 @@

 class _RunKeywordHandler(_PythonHandler):

+    def _wrap_with_signal_handling(self, runnable):
+        return runnable
+
     def _parse_arguments(self, handler_method):
arg_index = RUN_KW_REGISTER.get_args_to_process(self.library.orig_name,
                                                         self.name)


--
Subscription settings: 
http://groups.google.com/group/robotframework-commit/subscribe?hl=en

Reply via email to