From ff6f8151c92063a96fa0d1cfb5314da76abb529f Mon Sep 17 00:00:00 2001 From: Ben Niemann Date: Sat, 7 Oct 2017 16:31:02 +0200 Subject: [PATCH] Sanitize process class hierarchy. Also deflake process related tests. --- bin/runtests.py | 18 +-- noisicaa/audio_playground.py | 21 +--- noisicaa/audioproc/audioproc_client_test.py | 21 +--- noisicaa/audioproc/audioproc_process.py | 8 +- noisicaa/core/__init__.py | 4 +- noisicaa/core/process_manager.py | 125 ++++++++++++-------- noisicaa/core/process_manager_test.py | 33 +++--- noisicaa/editor_main.py | 10 +- noisicaa/instrument_db/client_test.py | 20 +--- noisicaa/instrument_db/process.py | 8 +- noisicaa/instrument_db/process_base.py | 5 +- noisicaa/music/player_integration_test.py | 25 +--- noisicaa/music/project_client_test.py | 41 +------ noisicaa/music/project_process.py | 8 +- noisicaa/node_db/client_test.py | 20 +--- noisicaa/node_db/process.py | 8 +- noisicaa/node_db/process_base.py | 5 +- noisicaa/ui/ui_process.py | 8 +- noisicaa/ui/uitest_utils.py | 54 ++------- 19 files changed, 163 insertions(+), 279 deletions(-) diff --git a/bin/runtests.py b/bin/runtests.py index da947537..fc2a8fd1 100755 --- a/bin/runtests.py +++ b/bin/runtests.py @@ -100,13 +100,17 @@ def main(argv): print(' '.join(subargv)) os.execv(subargv[0], subargv) - logging.basicConfig() - logging.getLogger().setLevel({ - 'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, - 'critical': logging.CRITICAL, + root_logger = logging.getLogger() + for handler in root_logger.handlers: + root_logger.removeHandler(handler) + logging.basicConfig( + format='%(levelname)-8s:%(process)5s:%(thread)08x:%(name)s: %(message)s', + level={ + 'debug': logging.DEBUG, + 'info': logging.INFO, + 'warning': logging.WARNING, + 'error': logging.ERROR, + 'critical': logging.CRITICAL, }[args.log_level]) if args.rebuild: diff --git a/noisicaa/audio_playground.py b/noisicaa/audio_playground.py index ae7b7eec..9318c59c 100644 --- a/noisicaa/audio_playground.py +++ b/noisicaa/audio_playground.py @@ -68,30 +68,13 @@ class AudioProcClient( self.window.handle_pipeline_status(status) -class AudioProcProcessImpl(object): - def __init__(self, event_loop): - super().__init__() - self.event_loop = event_loop - self.server = ipc.Server(self.event_loop, 'process') - - async def setup(self): - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - - -class AudioProcProcess( - audioproc_process.AudioProcProcessMixin, AudioProcProcessImpl): - pass - - class AudioPlaygroundApp(QtWidgets.QApplication): def __init__(self): super().__init__(['noisipg']) async def main(self, event_loop): - audioproc = AudioProcProcess(event_loop) + audioproc = audioproc_process.AudioProcProcess( + name='audioproc', event_loop=event_loop, manager=None) await audioproc.setup() try: window = AudioPlaygroundWindow(event_loop) diff --git a/noisicaa/audioproc/audioproc_client_test.py b/noisicaa/audioproc/audioproc_client_test.py index 2886d1ab..df617a81 100644 --- a/noisicaa/audioproc/audioproc_client_test.py +++ b/noisicaa/audioproc/audioproc_client_test.py @@ -52,24 +52,6 @@ class TestClient(audioproc_client.AudioProcClientMixin, TestClientImpl): pass -class TestAudioProcProcessImpl(object): - def __init__(self, event_loop): - super().__init__() - self.event_loop = event_loop - self.server = ipc.Server(self.event_loop, 'audioproc') - - async def setup(self): - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - - -class TestAudioProcProcess( - audioproc_process.AudioProcProcessMixin, TestAudioProcProcessImpl): - pass - - class ProxyTest(asynctest.TestCase): async def setUp(self): self.passthru_description = node_db.ProcessorDescription( @@ -89,7 +71,8 @@ class ProxyTest(asynctest.TestCase): direction=node_db.PortDirection.Output), ]) - self.audioproc_process = TestAudioProcProcess(self.loop) + self.audioproc_process = audioproc_process.AudioProcProcess( + name='audioproc', event_loop=self.loop, manager=None) await self.audioproc_process.setup() self.audioproc_task = self.loop.create_task( self.audioproc_process.run()) diff --git a/noisicaa/audioproc/audioproc_process.py b/noisicaa/audioproc/audioproc_process.py index 7950d71c..cc34ff5e 100644 --- a/noisicaa/audioproc/audioproc_process.py +++ b/noisicaa/audioproc/audioproc_process.py @@ -99,9 +99,9 @@ class Session(object): self.publish_mutation(self.pending_mutations.pop(0)) -class AudioProcProcessMixin(object): - def __init__(self, *args, shm=None, profile_path=None, **kwargs): - super().__init__(*args, **kwargs) +class AudioProcProcess(core.ProcessBase): + def __init__(self, *, shm=None, profile_path=None, **kwargs): + super().__init__(**kwargs) self.shm_name = shm self.profile_path = profile_path self.shm = None @@ -382,5 +382,5 @@ class AudioProcProcessMixin(object): self.__vm.dump() -class AudioProcProcess(AudioProcProcessMixin, core.ProcessImpl): +class AudioProcSubprocess(core.SubprocessMixin, AudioProcProcess): pass diff --git a/noisicaa/core/__init__.py b/noisicaa/core/__init__.py index 19b04437..04e94d32 100644 --- a/noisicaa/core/__init__.py +++ b/noisicaa/core/__init__.py @@ -33,7 +33,9 @@ from .model_base import ( DeferredReference, ) from .process_manager import ( - ProcessManager, ProcessImpl + ProcessManager, + ProcessBase, + SubprocessMixin, ) from .callbacks import ( CallbackRegistry, diff --git a/noisicaa/core/process_manager.py b/noisicaa/core/process_manager.py index b9dd14fc..15203cc5 100644 --- a/noisicaa/core/process_manager.py +++ b/noisicaa/core/process_manager.py @@ -244,9 +244,11 @@ class ChildCollector(object): self.__stop = threading.Event() self.__thread = threading.Thread(target=self.__main) self.__thread.start() + logger.info("Started ChildCollector thread 0x%08x", self.__thread.ident) def cleanup(self): if self.__thread is not None: + logger.info("Stopping ChildCollector thread 0x%08x", self.__thread.ident) self.__stop.set() self.__thread.join() self.__thread = None @@ -331,15 +333,19 @@ class ChildCollector(object): class ProcessManager(object): - def __init__(self, event_loop): + def __init__(self, event_loop, collect_stats=True): self._event_loop = event_loop self._processes = {} self._sigchld_received = asyncio.Event() self._server = ipc.Server(event_loop, 'manager') - self._stats_collector = stats.Collector() - self._child_collector = ChildCollector( - self._stats_collector) + + if collect_stats: + self._stats_collector = stats.Collector() + self._child_collector = ChildCollector(self._stats_collector) + else: + self._stats_collector = None + self._child_collector = None @property def server(self): @@ -356,10 +362,13 @@ class ProcessManager(object): 'STATS_FETCH', self.handle_stats_fetch) await self._server.setup() - self._child_collector.setup() + + if self._child_collector is not None: + self._child_collector.setup() async def cleanup(self): - self._child_collector.cleanup() + if self._child_collector is not None: + self._child_collector.cleanup() await self.terminate_all_children() await self._server.cleanup() @@ -420,8 +429,8 @@ class ProcessManager(object): for sig in signal.Signals: self._event_loop.remove_signal_handler(sig) - # Clear all stats inherited from the manager process. - stats.registry.clear() + # Create a new stats registry for this process. + stats.registry = stats.Registry() # Close the "other ends" of the pipes. os.close(request_out) @@ -494,7 +503,7 @@ class ProcessManager(object): proc.pid = pid proc.create_loggers() - proc.logger.info("Created new subprocess.") + proc.logger.info("Created new subprocess '%s' (%s).", name, cls) await proc.setup_std_handlers( self._event_loop, stdout_in, stderr_in, logger_in) @@ -505,7 +514,10 @@ class ProcessManager(object): stub_address = await child_connection.read_async(self._event_loop) - self._child_collector.add_child(pid, child_connection) + if self._child_collector is not None: + self._child_collector.add_child(pid, child_connection) + else: + child_connection.close() proc.address = stub_address.decode('utf-8') logger.info( @@ -575,13 +587,18 @@ class ProcessManager(object): dead_children.add(pid) for pid in dead_children: - self._child_collector.remove_child(pid) + if self._child_collector is not None: + self._child_collector.remove_child(pid) del self._processes[pid] def handle_stats_list(self): + if self._stats_collector is None: + return RuntimeError("Stats collection not enabled.") return self._stats_collector.list_stats() def handle_stats_fetch(self, expressions): + if self._stats_collector is None: + return RuntimeError("Stats collection not enabled.") return self._stats_collector.fetch_stats(expressions) @@ -596,10 +613,11 @@ class ChildConnectionHandler(object): self.__stop = eventfd.EventFD() self.__thread = threading.Thread(target=self.__main) self.__thread.start() + logger.info("Started ChildConnectionHandler thread 0x%08x", self.__thread.ident) def cleanup(self): if self.__thread is not None: - logger.info("Stopping ChildConnectionHandler...") + logger.info("Stopping ChildConnectionHandler thread 0x%08x...", self.__thread.ident) self.__stop.set() self.__thread.join() self.__thread = None @@ -633,16 +651,32 @@ class ChildConnectionHandler(object): logger.info("ChildConnectionHandler stopped.") -class ProcessImpl(object): - def __init__(self, name, manager_address): +class ProcessBase(object): + def __init__(self, *, name, manager, event_loop): self.name = name - self.manager_address = manager_address - self.event_loop = None - self.pid = os.getpid() + self.manager = manager + self.event_loop = event_loop + self.server = None - self.manager = None + async def setup(self): + self.server = ipc.Server(self.event_loop, self.name) + await self.server.setup() + + async def cleanup(self): + await self.server.cleanup() self.server = None + async def run(self): + raise NotImplementedError(type(self).__name__) + + +class SubprocessMixin(object): + def __init__(self, *, manager_address, **kwargs): + super().__init__(manager=None, event_loop=None, **kwargs) + + self.manager_address = manager_address + self.pid = os.getpid() + def create_event_loop(self): return asyncio.new_event_loop() @@ -664,53 +698,42 @@ class ProcessImpl(object): self.main_async(child_connection, *args, **kwargs)) finally: logger.info("Closing event loop...") - self.event_loop.stop() self.event_loop.run_until_complete( asyncio.gather(*asyncio.Task.all_tasks(self.event_loop))) + self.event_loop.stop() self.event_loop.close() logger.info("Event loop closed.") async def main_async(self, child_connection, *args, **kwargs): self.manager = ManagerStub(self.event_loop, self.manager_address) async with self.manager: - self.server = ipc.Server(self.event_loop, self.name) - async with self.server: - try: - logger.info("Setting up process.") - await self.setup() - - stub_address = self.server.address.encode('utf-8') - child_connection.write(stub_address) + try: + logger.info("Setting up process.") + await self.setup() - child_connection_handler = ChildConnectionHandler(child_connection) - child_connection_handler.setup() - try: - logger.info("Entering run method.") - return await self.run(*args, **kwargs) + stub_address = self.server.address.encode('utf-8') + child_connection.write(stub_address) - except Exception as exc: - logger.error( - "Unhandled exception in process %s:\n%s", - self.name, traceback.format_exc()) - raise + child_connection_handler = ChildConnectionHandler(child_connection) + child_connection_handler.setup() + try: + logger.info("Entering run method.") + return await self.run(*args, **kwargs) - finally: - logger.info("Closing child connection...") - child_connection_handler.cleanup() - child_connection.close() - logger.info("Child connection closed.") + except Exception as exc: + logger.error( + "Unhandled exception in process %s:\n%s", + self.name, traceback.format_exc()) + raise finally: - await self.cleanup() - - async def setup(self): - pass + logger.info("Closing child connection...") + child_connection_handler.cleanup() + child_connection.close() + logger.info("Child connection closed.") - async def cleanup(self): - pass - - async def run(self): - raise NotImplementedError("Subclass must override run") + finally: + await self.cleanup() class SetPIDHandler(logging.Handler): diff --git a/noisicaa/core/process_manager_test.py b/noisicaa/core/process_manager_test.py index 277a7069..11de16b6 100644 --- a/noisicaa/core/process_manager_test.py +++ b/noisicaa/core/process_manager_test.py @@ -33,74 +33,69 @@ from . import process_manager class ProcessManagerTest(asynctest.TestCase): - @unittest.skip("FIXME: test hangs infinitely.") async def test_simple(self): - class Child(process_manager.ProcessImpl): - def __init__(self, foo, **kwargs): + class Child(process_manager.SubprocessMixin, process_manager.ProcessBase): + def __init__(self, *, foo, **kwargs): super().__init__(**kwargs) assert foo == 'bar' async def run(self): pass - async with process_manager.ProcessManager(self.loop) as mgr: + async with process_manager.ProcessManager(self.loop, collect_stats=False) as mgr: proc = await mgr.start_process('test', Child, foo='bar') await proc.wait() self.assertEqual(proc.returncode, 0) - @unittest.skip("FIXME: test hangs infinitely.") async def test_child_fails(self): - class Child(process_manager.ProcessImpl): + class Child(process_manager.SubprocessMixin, process_manager.ProcessBase): async def run(self): - sys.exit(2) + os._exit(2) - async with process_manager.ProcessManager(self.loop) as mgr: + async with process_manager.ProcessManager(self.loop, collect_stats=False) as mgr: proc = await mgr.start_process('test', Child) await proc.wait() self.assertEqual(proc.returncode, 2) - @unittest.skip("FIXME: test hangs infinitely.") async def test_child_killed(self): - class Child(process_manager.ProcessImpl): + class Child(process_manager.SubprocessMixin, process_manager.ProcessBase): async def run(self): os.kill(self.pid, signal.SIGKILL) - async with process_manager.ProcessManager(self.loop) as mgr: + async with process_manager.ProcessManager(self.loop, collect_stats=False) as mgr: proc = await mgr.start_process('test', Child) await proc.wait() self.assertEqual(proc.returncode, 1) self.assertEqual(proc.signal, signal.SIGKILL) - @unittest.skip("FIXME: test hangs infinitely.") async def test_left_over(self): - class Child(process_manager.ProcessImpl): + class Child(process_manager.SubprocessMixin, process_manager.ProcessBase): async def run(self): while True: await asyncio.sleep(1) - async with process_manager.ProcessManager(self.loop) as mgr: + async with process_manager.ProcessManager(self.loop, collect_stats=False) as mgr: stub = await mgr.start_process('test', Child) - @unittest.skip("FIXME: test hangs infinitely.") async def test_left_over_sigterm_fails(self): - class Child(process_manager.ProcessImpl): + class Child(process_manager.SubprocessMixin, process_manager.ProcessBase): async def run(self): signal.signal(signal.SIGTERM, signal.SIG_IGN) while True: await asyncio.sleep(1) - async with process_manager.ProcessManager(self.loop) as mgr: + async with process_manager.ProcessManager(self.loop, collect_stats=False) as mgr: stub = await mgr.start_process('test', Child) await mgr.terminate_all_children(timeout=0.2) async def test_capture_stdout(self): - class Child(process_manager.ProcessImpl): + class Child(process_manager.SubprocessMixin, process_manager.ProcessBase): async def run(self): for i in range(10): print(i) sys.stderr.write('goo') - async with process_manager.ProcessManager(self.loop) as mgr: + async with process_manager.ProcessManager(self.loop, collect_stats=False) as mgr: proc = await mgr.start_process('test', Child) await proc.wait() self.assertEqual(proc.returncode, 0) diff --git a/noisicaa/editor_main.py b/noisicaa/editor_main.py index a1c5040f..2078a679 100644 --- a/noisicaa/editor_main.py +++ b/noisicaa/editor_main.py @@ -99,7 +99,7 @@ class Editor(object): while True: next_retry = time.time() + 5 proc = await self.manager.start_process( - 'ui', 'noisicaa.ui.ui_process.UIProcess', + 'ui', 'noisicaa.ui.ui_process.UISubprocess', runtime_settings=self.runtime_settings, paths=self.paths) await proc.wait() @@ -141,7 +141,7 @@ class Editor(object): # TODO: keep map of uri->proc, only create processes for new # URIs. proc = await self.manager.start_process( - 'project', 'noisicaa.music.project_process.ProjectProcess') + 'project', 'noisicaa.music.project_process.ProjectSubprocess') return proc.address async def handle_create_audioproc_process(self, name, **kwargs): @@ -149,7 +149,7 @@ class Editor(object): # names. proc = await self.manager.start_process( 'audioproc<%s>' % name, - 'noisicaa.audioproc.audioproc_process.AudioProcProcess', + 'noisicaa.audioproc.audioproc_process.AudioProcSubprocess', **kwargs) return proc.address @@ -158,7 +158,7 @@ class Editor(object): if self.node_db_process is None: self.node_db_process = await self.manager.start_process( 'node_db', - 'noisicaa.node_db.process.NodeDBProcess') + 'noisicaa.node_db.process.NodeDBSubprocess') return self.node_db_process.address @@ -167,7 +167,7 @@ class Editor(object): if self.instrument_db_process is None: self.instrument_db_process = await self.manager.start_process( 'instrument_db', - 'noisicaa.instrument_db.process.InstrumentDBProcess') + 'noisicaa.instrument_db.process.InstrumentDBSubprocess') return self.instrument_db_process.address diff --git a/noisicaa/instrument_db/client_test.py b/noisicaa/instrument_db/client_test.py index 95696d6f..ddff7230 100644 --- a/noisicaa/instrument_db/client_test.py +++ b/noisicaa/instrument_db/client_test.py @@ -51,26 +51,10 @@ class TestClient(client.InstrumentDBClientMixin, TestClientImpl): pass -class TestProcessImpl(object): - def __init__(self, event_loop): - super().__init__() - self.event_loop = event_loop - self.server = ipc.Server(self.event_loop, 'audioproc') - - async def setup(self): - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - - -class TestProcess(process.InstrumentDBProcessMixin, TestProcessImpl): - pass - - class InstrumentDBClientTest(asynctest.TestCase): async def setUp(self): - self.process = TestProcess(self.loop) + self.process = process.InstrumentDBProcess( + name='instrument_db', event_loop=self.loop, manager=None) await self.process.setup() self.process_task = self.loop.create_task( self.process.run()) diff --git a/noisicaa/instrument_db/process.py b/noisicaa/instrument_db/process.py index eaf7ee87..745ca5d8 100644 --- a/noisicaa/instrument_db/process.py +++ b/noisicaa/instrument_db/process.py @@ -80,9 +80,9 @@ class Session(object): self.pending_mutations.clear() -class InstrumentDBProcessMixin(process_base.InstrumentDBProcessBase): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) +class InstrumentDBProcess(process_base.InstrumentDBProcessBase): + def __init__(self, **kwargs): + super().__init__(**kwargs) self.sessions = {} self.db = None self.search_paths = [ @@ -168,5 +168,5 @@ class InstrumentDBProcessMixin(process_base.InstrumentDBProcessBase): return self.db.start_scan(self.search_paths, True) -class InstrumentDBProcess(InstrumentDBProcessMixin, core.ProcessImpl): +class InstrumentDBSubprocess(core.SubprocessMixin, InstrumentDBProcess): pass diff --git a/noisicaa/instrument_db/process_base.py b/noisicaa/instrument_db/process_base.py index b2cc7e9a..67ca3a4d 100644 --- a/noisicaa/instrument_db/process_base.py +++ b/noisicaa/instrument_db/process_base.py @@ -20,7 +20,10 @@ # # @end:license -class InstrumentDBProcessBase(object): +from noisicaa import core + + +class InstrumentDBProcessBase(core.ProcessBase): async def setup(self): await super().setup() diff --git a/noisicaa/music/player_integration_test.py b/noisicaa/music/player_integration_test.py index 0e46d8ac..f9a59cea 100644 --- a/noisicaa/music/player_integration_test.py +++ b/noisicaa/music/player_integration_test.py @@ -57,24 +57,6 @@ from . import project_client logger = logging.getLogger(__name__) -class TestAudioProcProcessImpl(object): - def __init__(self, event_loop, name): - super().__init__() - self.event_loop = event_loop - self.server = ipc.Server(self.event_loop, name) - - async def setup(self): - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - - -class TestAudioProcProcess( - audioproc_process.AudioProcProcessMixin, TestAudioProcProcessImpl): - pass - - class TestAudioProcClientImpl(object): def __init__(self, event_loop, name): super().__init__() @@ -137,7 +119,8 @@ class PlayerTest(asynctest.TestCase): self.callback_server = CallbackServer(self.loop) await self.callback_server.setup() - self.audioproc_server_main = TestAudioProcProcess(self.loop, 'main_process') + self.audioproc_server_main = audioproc_process.AudioProcProcess( + name='main_process', event_loop=self.loop, manager=None) await self.audioproc_server_main.setup() self.audioproc_server_main_task = self.loop.create_task( self.audioproc_server_main.run()) @@ -151,8 +134,8 @@ class PlayerTest(asynctest.TestCase): profile_path = None if constants.TEST_OPTS.ENABLE_PROFILER: profile_path = os.path.join(tempfile.gettempdir(), self.id() + '.prof') - self.audioproc_server_player = TestAudioProcProcess( - self.loop, 'player_process', + self.audioproc_server_player = audioproc_process.AudioProcProcess( + name='player_process', event_loop=self.loop, manager=None, profile_path=profile_path) await self.audioproc_server_player.setup() self.audioproc_server_player_task = self.loop.create_task( diff --git a/noisicaa/music/project_client_test.py b/noisicaa/music/project_client_test.py index 0715070b..109d84eb 100644 --- a/noisicaa/music/project_client_test.py +++ b/noisicaa/music/project_client_test.py @@ -55,25 +55,6 @@ class TestClient(project_client.ProjectClientMixin, TestClientImpl): pass -class TestProjectProcessImpl(object): - def __init__(self, event_loop, manager): - super().__init__() - self.event_loop = event_loop - self.manager = manager - self.server = ipc.Server(self.event_loop, 'project') - - async def setup(self): - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - - -class TestProjectProcess( - project_process.ProjectProcessMixin, TestProjectProcessImpl): - pass - - class AsyncSetupBase(): async def setup(self): pass @@ -81,20 +62,7 @@ class AsyncSetupBase(): async def cleanup(self): pass -class TestNodeDBProcess(node_db.NodeDBProcessBase, AsyncSetupBase): - def __init__(self, event_loop): - super().__init__() - self.event_loop = event_loop - self.server = ipc.Server(self.event_loop, 'node_db') - - async def setup(self): - await super().setup() - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - await super().cleanup() - +class TestNodeDBProcess(node_db.NodeDBProcessBase): def handle_start_session(self, client_address, flags): return '123' @@ -104,7 +72,8 @@ class TestNodeDBProcess(node_db.NodeDBProcessBase, AsyncSetupBase): class ProxyTest(asynctest.TestCase): async def setUp(self): - self.node_db_process = TestNodeDBProcess(self.loop) + self.node_db_process = TestNodeDBProcess( + name='node_db', event_loop=self.loop, manager=None) await self.node_db_process.setup() self.manager = mock.Mock() @@ -113,8 +82,10 @@ class ProxyTest(asynctest.TestCase): return self.node_db_process.server.address self.manager.call.side_effect = mock_call - self.project_process = TestProjectProcess(self.loop, self.manager) + self.project_process = project_process.ProjectProcess( + name='project', manager=self.manager, event_loop=self.loop) await self.project_process.setup() + self.client = TestClient(self.loop) self.client.cls_map = model.cls_map await self.client.setup() diff --git a/noisicaa/music/project_process.py b/noisicaa/music/project_process.py index 95ecd1e5..4a7b5501 100644 --- a/noisicaa/music/project_process.py +++ b/noisicaa/music/project_process.py @@ -186,9 +186,9 @@ class NodeDBClient(node_db.NodeDBClientMixin, NodeDBClientImpl): pass -class ProjectProcessMixin(object): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) +class ProjectProcess(core.ProcessBase): + def __init__(self, **kwargs): + super().__init__(**kwargs) self._shutting_down = None @@ -488,5 +488,5 @@ class ProjectProcessMixin(object): session.set_values(data, from_client=True) -class ProjectProcess(ProjectProcessMixin, core.ProcessImpl): +class ProjectSubprocess(core.SubprocessMixin, ProjectProcess): pass diff --git a/noisicaa/node_db/client_test.py b/noisicaa/node_db/client_test.py index ba72a2a5..12922e6a 100644 --- a/noisicaa/node_db/client_test.py +++ b/noisicaa/node_db/client_test.py @@ -51,26 +51,10 @@ class TestClient(client.NodeDBClientMixin, TestClientImpl): pass -class TestProcessImpl(object): - def __init__(self, event_loop): - super().__init__() - self.event_loop = event_loop - self.server = ipc.Server(self.event_loop, 'audioproc') - - async def setup(self): - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - - -class TestProcess(process.NodeDBProcessMixin, TestProcessImpl): - pass - - class NodeDBClientTest(asynctest.TestCase): async def setUp(self): - self.process = TestProcess(self.loop) + self.process = process.NodeDBProcess( + name='node_db', event_loop=self.loop, manager=None) await self.process.setup() self.process_task = self.loop.create_task( self.process.run()) diff --git a/noisicaa/node_db/process.py b/noisicaa/node_db/process.py index eee7c2c0..ad5deaa4 100644 --- a/noisicaa/node_db/process.py +++ b/noisicaa/node_db/process.py @@ -54,9 +54,9 @@ class Session(object): await self.callback_stub.call('NODEDB_MUTATION', mutation) -class NodeDBProcessMixin(process_base.NodeDBProcessBase): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) +class NodeDBProcess(process_base.NodeDBProcessBase): + def __init__(self, **kwargs): + super().__init__(**kwargs) self.sessions = {} self.db = db.NodeDB() @@ -117,5 +117,5 @@ class NodeDBProcessMixin(process_base.NodeDBProcessBase): return self.db.start_scan() -class NodeDBProcess(NodeDBProcessMixin, core.ProcessImpl): +class NodeDBSubprocess(core.SubprocessMixin, NodeDBProcess): pass diff --git a/noisicaa/node_db/process_base.py b/noisicaa/node_db/process_base.py index 476a9cb3..0c1c8931 100644 --- a/noisicaa/node_db/process_base.py +++ b/noisicaa/node_db/process_base.py @@ -20,7 +20,10 @@ # # @end:license -class NodeDBProcessBase(object): +from noisicaa import core + + +class NodeDBProcessBase(core.ProcessBase): async def setup(self): await super().setup() diff --git a/noisicaa/ui/ui_process.py b/noisicaa/ui/ui_process.py index a5edb6e2..8fa2d316 100644 --- a/noisicaa/ui/ui_process.py +++ b/noisicaa/ui/ui_process.py @@ -34,8 +34,8 @@ from . import editor_app logger = logging.getLogger(__name__) -class UIProcessMixin(object): - def __init__(self, runtime_settings, paths, **kwargs): +class UISubprocess(core.SubprocessMixin, core.ProcessBase): + def __init__(self, *, runtime_settings, paths, **kwargs): super().__init__(**kwargs) self.app = self.create_app(self, runtime_settings, paths) @@ -69,7 +69,3 @@ class UIProcessMixin(object): def handle_signal(self, sig): logger.info("%s received.", sig.name) self.quit(0) - - -class UIProcess(UIProcessMixin, core.ProcessImpl): - pass diff --git a/noisicaa/ui/uitest_utils.py b/noisicaa/ui/uitest_utils.py index 4ae3eb49..c4442f7b 100644 --- a/noisicaa/ui/uitest_utils.py +++ b/noisicaa/ui/uitest_utils.py @@ -30,6 +30,7 @@ import asynctest from PyQt5.QtCore import Qt from PyQt5 import QtGui +from noisicaa import core from noisicaa import instrument_db from noisicaa import node_db from noisicaa.core import ipc @@ -139,20 +140,7 @@ class AsyncSetupBase(): pass -class TestNodeDBProcess(node_db.NodeDBProcessBase, AsyncSetupBase): - def __init__(self, event_loop): - super().__init__() - self.event_loop = event_loop - self.server = ipc.Server(self.event_loop, 'node_db') - - async def setup(self): - await super().setup() - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - await super().cleanup() - +class TestNodeDBProcess(node_db.NodeDBProcessBase): def handle_start_session(self, client_address, flags): return '123' @@ -163,20 +151,7 @@ class TestNodeDBProcess(node_db.NodeDBProcessBase, AsyncSetupBase): pass -class TestInstrumentDBProcess(instrument_db.InstrumentDBProcessBase, AsyncSetupBase): - def __init__(self, event_loop): - super().__init__() - self.event_loop = event_loop - self.server = ipc.Server(self.event_loop, 'instrument_db') - - async def setup(self): - await super().setup() - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() - await super().cleanup() - +class TestInstrumentDBProcess(instrument_db.InstrumentDBProcessBase): def handle_start_session(self, client_address, flags): return '123' @@ -187,18 +162,10 @@ class TestInstrumentDBProcess(instrument_db.InstrumentDBProcessBase, AsyncSetupB pass -class MockProcess(object): - def __init__(self, event_loop, manager): - self.event_loop = event_loop - self.manager = manager +class MockProcess(core.ProcessBase): + def __init__(self, **kwargs): + super().__init__(**kwargs) self.project = None - self.server = ipc.Server(self.event_loop, 'ui') - - async def setup(self): - await self.server.setup() - - async def cleanup(self): - await self.server.cleanup() class MockApp(BaseEditorApp): @@ -221,10 +188,12 @@ class UITest(asynctest.TestCase): app = None async def setUp(self): - self.node_db_process = TestNodeDBProcess(self.loop) + self.node_db_process = TestNodeDBProcess( + name='node_db', event_loop=self.loop, manager=None) await self.node_db_process.setup() - self.instrument_db_process = TestInstrumentDBProcess(self.loop) + self.instrument_db_process = TestInstrumentDBProcess( + name='instrument_db', event_loop=self.loop, manager=None) await self.instrument_db_process.setup() self.manager = mock.Mock() @@ -238,7 +207,8 @@ class UITest(asynctest.TestCase): self.manager.call.side_effect = mock_call - self.process = MockProcess(self.loop, self.manager) + self.process = MockProcess( + name='ui', event_loop=self.loop, manager=self.manager) await self.process.setup() if UITest.app is None: