diff --git a/mycroft/lock/__init__.py b/mycroft/lock/__init__.py index 86b6ab2ab4..af7baebc10 100644 --- a/mycroft/lock/__init__.py +++ b/mycroft/lock/__init__.py @@ -187,8 +187,11 @@ class Lock(object): # python 3+ 'class Lock' *args: Ignored. Required as this fuction is called as a signel handler. ''' - with open(self.path, 'r') as L: - if self.__pid == L.read(): - os.unlink(self.path) - + try: + with open(self.path, 'r') as L: + pid = int(L.read()) + if self.__pid == pid: + os.unlink(self.path) + except IOError: + pass # End class Lock diff --git a/mycroft/messagebus/service/main.py b/mycroft/messagebus/service/main.py index 77eafade79..e04218affa 100644 --- a/mycroft/messagebus/service/main.py +++ b/mycroft/messagebus/service/main.py @@ -17,6 +17,7 @@ import tornado.ioloop as ioloop import tornado.web as web +import tornado.autoreload as autoreload from mycroft.configuration import ConfigurationManager from mycroft.messagebus.service.ws import WebsocketEventHandler @@ -35,6 +36,13 @@ def main(): import tornado.options lock = Lock("service") tornado.options.parse_command_line() + + def reload_hook(): + """ Hook to release lock when autoreload is triggered. """ + lock.delete() + + tornado.autoreload.add_reload_hook(reload_hook) + config = ConfigurationManager.get().get("websocket") host = config.get("host") diff --git a/requirements.txt b/requirements.txt index b95683858a..b8ec3e9b7c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,4 +41,5 @@ urllib5==5.0.0 pyric==0.1.6 inflection==0.3.1 uuid==1.30 -pytz==2017.2 \ No newline at end of file +pytz==2017.2 +mock diff --git a/test/lock/__init__.py b/test/lock/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/lock/test_lock.py b/test/lock/test_lock.py new file mode 100644 index 0000000000..f14edb4eaf --- /dev/null +++ b/test/lock/test_lock.py @@ -0,0 +1,46 @@ +from os.path import dirname, join, exists, isfile +import os +import signal +import unittest +import mock +from shutil import rmtree +from mycroft.lock import Lock + + +class TestLock(unittest.TestCase): + def setUp(self): + if exists('/tmp/mycroft'): + rmtree('/tmp/mycroft') + + def test_create_lock(self): + l1 = Lock('test') + self.assertTrue(isfile('/tmp/mycroft/test.pid')) + + def test_delete_lock(self): + l1 = Lock('test') + self.assertTrue(isfile('/tmp/mycroft/test.pid')) + l1.delete() + self.assertFalse(isfile('/tmp/mycroft/test.pid')) + + @mock.patch('os.kill') + def test_existing_lock(self, mock_kill): + """ Test that an existing lock will kill the old pid. """ + l1 = Lock('test') + self.assertTrue(isfile('/tmp/mycroft/test.pid')) + l2 = Lock('test2') + self.assertFalse(mock_kill.called) + l2 = Lock('test') + self.assertTrue(mock_kill.called) + + def test_keyboard_interrupt(self): + l1 = Lock('test') + self.assertTrue(isfile('/tmp/mycroft/test.pid')) + try: + os.kill(os.getpid(), signal.SIGINT) + except KeyboardInterrupt: + pass + self.assertFalse(isfile('/tmp/mycroft/test.pid')) + + +if __name__ == '__main__': + unittest.main()