Store temp files (sockets, pipes) in a new directory and clean up on exit.
parent
4ecce2673a
commit
825dbf5b58
16
NOTES.org
16
NOTES.org
|
@ -11,16 +11,6 @@
|
|||
Sometimes still hangs on shutdown. Subprocess calls _exit(), but manager doesn't seem to get the
|
||||
SIGCHLD. Non-deterministic and rare, so hard to debug...
|
||||
|
||||
* Cleanup temp files on shutdown :FR:
|
||||
- store sockets, etc. in separate directory
|
||||
- directory is chosen by ProcessManager and propagated to subprocesses
|
||||
- cleaned up on exit
|
||||
- still leaves a dead directory around on unclean shutdown, SIGKILL, etc.
|
||||
- put in /tmp and rely on OS to cleanup junk
|
||||
- on startup try to find dead directories and clean them up
|
||||
- take a lock, which is automatically released by OS
|
||||
- in tests, runtests manages directory and same principles apply
|
||||
|
||||
* Visual feedback when opening project :FR:
|
||||
- Create tab first, show some spinning wheel, until project is setup completely.
|
||||
|
||||
|
@ -199,6 +189,12 @@ Is there some cross-compiler/-platform header to provide this functionality?
|
|||
|
||||
* Make sample rate configurable :FR:
|
||||
- all processors need to cleanup/setup on changes
|
||||
* Cleanup temp files on shutdown :FR:
|
||||
- still leaves a dead directory around on unclean shutdown, SIGKILL, etc.
|
||||
- put in /tmp and rely on OS to cleanup junk
|
||||
- on startup try to find dead directories and clean them up
|
||||
- take a lock, which is automatically released by OS
|
||||
|
||||
* crash on shutdown, when csound wants to log after LogSink has been destroyed :CRASH:
|
||||
- is HostData properly cleaned up?
|
||||
* turn off all notes when playback gets paused :FR:
|
||||
|
|
|
@ -24,6 +24,7 @@ import asyncio
|
|||
|
||||
from noisidev import unittest
|
||||
from noisicaa import node_db
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
from noisicaa.core import ipc
|
||||
|
||||
from . import audioproc_process
|
||||
|
@ -34,7 +35,7 @@ class TestClientImpl(object):
|
|||
def __init__(self, event_loop):
|
||||
super().__init__()
|
||||
self.event_loop = event_loop
|
||||
self.server = ipc.Server(self.event_loop, 'client')
|
||||
self.server = ipc.Server(self.event_loop, 'client', TEST_OPTS.TMP_DIR)
|
||||
|
||||
async def setup(self):
|
||||
await self.server.setup()
|
||||
|
@ -48,6 +49,13 @@ class TestClient(audioproc_client.AudioProcClientMixin, TestClientImpl):
|
|||
|
||||
|
||||
class ProxyTest(unittest.AsyncTestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.client = None
|
||||
self.audioproc_task = None
|
||||
self.audioproc_process = None
|
||||
|
||||
async def setup_testcase(self):
|
||||
self.passthru_description = node_db.ProcessorDescription(
|
||||
processor_name='null',
|
||||
|
@ -67,19 +75,22 @@ class ProxyTest(unittest.AsyncTestCase):
|
|||
])
|
||||
|
||||
self.audioproc_process = audioproc_process.AudioProcProcess(
|
||||
name='audioproc', event_loop=self.loop, manager=None)
|
||||
name='audioproc', event_loop=self.loop, manager=None, tmp_dir=TEST_OPTS.TMP_DIR)
|
||||
await self.audioproc_process.setup()
|
||||
self.audioproc_task = self.loop.create_task(
|
||||
self.audioproc_process.run())
|
||||
self.audioproc_task = self.loop.create_task(self.audioproc_process.run())
|
||||
self.client = TestClient(self.loop)
|
||||
await self.client.setup()
|
||||
await self.client.connect(self.audioproc_process.server.address)
|
||||
|
||||
async def cleanup_testcase(self):
|
||||
await self.client.disconnect(shutdown=True)
|
||||
await self.client.cleanup()
|
||||
await asyncio.wait_for(self.audioproc_task, None)
|
||||
await self.audioproc_process.cleanup()
|
||||
if self.client is not None:
|
||||
await self.client.disconnect(shutdown=True)
|
||||
await self.client.cleanup()
|
||||
if self.audioproc_process is not None:
|
||||
if self.audioproc_task is not None:
|
||||
await self.audioproc_process.shutdown()
|
||||
await asyncio.wait_for(self.audioproc_task, None)
|
||||
await self.audioproc_process.cleanup()
|
||||
|
||||
async def test_add_remove_node(self):
|
||||
await self.client.add_node(id='test', description=self.passthru_description)
|
||||
|
|
|
@ -217,6 +217,13 @@ class AudioProcProcess(core.ProcessBase):
|
|||
logger.info("Pipeline finished.")
|
||||
self.__shutdown_complete.set()
|
||||
|
||||
async def shutdown(self):
|
||||
logger.info("Shutdown received.")
|
||||
self.__shutting_down.set()
|
||||
logger.info("Waiting for shutdown to complete...")
|
||||
await self.__shutdown_complete.wait()
|
||||
logger.info("Shutdown complete.")
|
||||
|
||||
def get_session(self, session_id):
|
||||
try:
|
||||
return self.sessions[session_id]
|
||||
|
@ -274,11 +281,7 @@ class AudioProcProcess(core.ProcessBase):
|
|||
del self.sessions[session_id]
|
||||
|
||||
async def handle_shutdown(self):
|
||||
logger.info("Shutdown received.")
|
||||
self.__shutting_down.set()
|
||||
logger.info("Waiting for shutdown to complete...")
|
||||
await self.__shutdown_complete.wait()
|
||||
logger.info("Shutdown complete.")
|
||||
await self.shutdown()
|
||||
|
||||
async def handle_pipeline_mutation(self, session_id, mutation):
|
||||
self.get_session(session_id)
|
||||
|
|
|
@ -21,19 +21,17 @@
|
|||
import os
|
||||
import os.path
|
||||
import uuid
|
||||
import tempfile
|
||||
import threading
|
||||
|
||||
from noisidev import unittest
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
from . import audio_stream
|
||||
|
||||
|
||||
class TestAudioStream(unittest.TestCase):
|
||||
def setup_testcase(self):
|
||||
self.address = os.fsencode(
|
||||
os.path.join(
|
||||
tempfile.gettempdir(),
|
||||
'test.%s.pipe' % uuid.uuid4().hex))
|
||||
os.path.join(TEST_OPTS.TMP_DIR, 'test.%s.pipe' % uuid.uuid4().hex))
|
||||
|
||||
def test_client_to_server(self):
|
||||
server = audio_stream.AudioStream.create_server(self.address)
|
||||
|
|
|
@ -23,13 +23,13 @@ from libcpp.memory cimport unique_ptr
|
|||
import os
|
||||
import os.path
|
||||
import struct
|
||||
import tempfile
|
||||
import uuid
|
||||
import threading
|
||||
|
||||
import capnp
|
||||
|
||||
from noisidev import unittest
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
from noisicaa.core.status cimport *
|
||||
from noisicaa.core.status import *
|
||||
from . import audio_stream
|
||||
|
@ -52,9 +52,7 @@ class TestIPCBackend(unittest.TestCase):
|
|||
vm.reset(new VM(host_data.get(), NULL))
|
||||
|
||||
cdef PyBackendSettings backend_settings = PyBackendSettings(
|
||||
ipc_address=os.path.join(
|
||||
tempfile.gettempdir(),
|
||||
'test.%s.pipe' % uuid.uuid4().hex))
|
||||
ipc_address=os.path.join(TEST_OPTS.TMP_DIR, 'test.%s.pipe' % uuid.uuid4().hex))
|
||||
|
||||
cdef StatusOr[Backend*] stor_backend = Backend.create(b"ipc", backend_settings.get())
|
||||
check(stor_backend)
|
||||
|
|
|
@ -26,12 +26,12 @@ import threading
|
|||
import uuid
|
||||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
import struct
|
||||
|
||||
import capnp
|
||||
|
||||
from noisidev import unittest
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
from noisicaa.core.status cimport *
|
||||
from noisicaa.core.status import ConnectionClosed
|
||||
from . import block_data_capnp
|
||||
|
@ -51,9 +51,7 @@ class TestProcessorIPC(unittest.TestCase):
|
|||
host_data.reset(new HostData())
|
||||
|
||||
address = os.fsencode(
|
||||
os.path.join(
|
||||
tempfile.gettempdir(),
|
||||
'test.%s.pipe' % uuid.uuid4().hex))
|
||||
os.path.join(TEST_OPTS.TMP_DIR, 'test.%s.pipe' % uuid.uuid4().hex))
|
||||
|
||||
cdef StatusOr[Processor*] stor_processor = Processor.create(
|
||||
b'test_node', host_data.get(), b'ipc')
|
||||
|
|
|
@ -59,6 +59,7 @@ class TEST_OPTS(object):
|
|||
WRITE_PERF_STATS = False
|
||||
ENABLE_PROFILER = False
|
||||
PLAYBACK_BACKEND = 'null'
|
||||
TMP_DIR = '/tmp'
|
||||
|
||||
# Cleanup namespace
|
||||
del os
|
||||
|
|
|
@ -28,7 +28,6 @@ import os
|
|||
import os.path
|
||||
import pickle
|
||||
import pprint
|
||||
import tempfile
|
||||
import traceback
|
||||
import uuid
|
||||
|
||||
|
@ -138,17 +137,13 @@ class Server(object):
|
|||
pickle.dumps, protocol=pickle.HIGHEST_PROTOCOL)
|
||||
deserialize = pickle.loads
|
||||
|
||||
def __init__(self, event_loop, name, socket_dir=None):
|
||||
def __init__(self, event_loop, name, socket_dir):
|
||||
self.event_loop = event_loop
|
||||
self.name = name
|
||||
|
||||
self.logger = logger.getChild(name)
|
||||
|
||||
if socket_dir is None:
|
||||
socket_dir = tempfile.gettempdir()
|
||||
|
||||
self.address = os.path.join(
|
||||
socket_dir, '%s.%s.sock' % (self.name, uuid.uuid4().hex))
|
||||
self.address = os.path.join(socket_dir, '%s.%s.sock' % (self.name, uuid.uuid4().hex))
|
||||
|
||||
self._next_connection_id = 0
|
||||
self._server = None
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
# @end:license
|
||||
|
||||
from noisidev import unittest
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
from . import ipc
|
||||
|
||||
|
||||
class IPCTest(unittest.AsyncTestCase):
|
||||
async def test_ping(self):
|
||||
async with ipc.Server(self.loop, name='test') as server:
|
||||
async with ipc.Server(self.loop, name='test', socket_dir=TEST_OPTS.TMP_DIR) as server:
|
||||
async with ipc.Stub(self.loop, server.address) as stub:
|
||||
await stub.ping()
|
||||
await stub.ping()
|
||||
|
@ -36,7 +37,7 @@ class IPCTest(unittest.AsyncTestCase):
|
|||
await stub.ping()
|
||||
|
||||
async def test_command(self):
|
||||
async with ipc.Server(self.loop, name='test') as server:
|
||||
async with ipc.Server(self.loop, name='test', socket_dir=TEST_OPTS.TMP_DIR) as server:
|
||||
server.add_command_handler('foo', lambda: None)
|
||||
server.add_command_handler('bar', lambda: 'yo')
|
||||
server.add_command_handler('gnurz', lambda a: a + 1)
|
||||
|
@ -47,14 +48,14 @@ class IPCTest(unittest.AsyncTestCase):
|
|||
self.assertEqual(await stub.call('gnurz', 3), 4)
|
||||
|
||||
async def test_remote_exception(self):
|
||||
async with ipc.Server(self.loop, name='test') as server:
|
||||
async with ipc.Server(self.loop, name='test', socket_dir=TEST_OPTS.TMP_DIR) as server:
|
||||
server.add_command_handler('foo', lambda: 1/0)
|
||||
async with ipc.Stub(self.loop, server.address) as stub:
|
||||
with self.assertRaises(ipc.RemoteException):
|
||||
await stub.call('foo')
|
||||
|
||||
async def test_async_handler(self):
|
||||
async with ipc.Server(self.loop, name='test') as server:
|
||||
async with ipc.Server(self.loop, name='test', socket_dir=TEST_OPTS.TMP_DIR) as server:
|
||||
async def handler(arg):
|
||||
return arg + 1
|
||||
server.add_command_handler('foo', handler)
|
||||
|
|
|
@ -28,9 +28,11 @@ import logging
|
|||
import os
|
||||
import pickle
|
||||
import select
|
||||
import shutil
|
||||
import signal
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
@ -337,7 +339,8 @@ class ProcessManager(object):
|
|||
self._processes = {}
|
||||
self._sigchld_received = asyncio.Event()
|
||||
|
||||
self._server = ipc.Server(event_loop, 'manager')
|
||||
self._tmp_dir = None
|
||||
self._server = None
|
||||
|
||||
if collect_stats:
|
||||
self._stats_collector = stats.Collector()
|
||||
|
@ -355,6 +358,12 @@ class ProcessManager(object):
|
|||
self._event_loop.add_signal_handler(
|
||||
signal.SIGCHLD, self.sigchld_handler)
|
||||
|
||||
self._tmp_dir = tempfile.mkdtemp(
|
||||
prefix='noisicaa-%s-%d-' % (time.strftime('%Y%m%d-%H%M%S'), os.getpid()))
|
||||
logger.info("Using %s for temp files.", self._tmp_dir)
|
||||
|
||||
self._server = ipc.Server(self._event_loop, 'manager', socket_dir=self._tmp_dir)
|
||||
|
||||
self._server.add_command_handler(
|
||||
'STATS_LIST', self.handle_stats_list)
|
||||
self._server.add_command_handler(
|
||||
|
@ -370,10 +379,17 @@ class ProcessManager(object):
|
|||
self._child_collector.cleanup()
|
||||
|
||||
await self.terminate_all_children()
|
||||
await self._server.cleanup()
|
||||
if self._server is not None:
|
||||
await self._server.cleanup()
|
||||
|
||||
self._server.remove_command_handler('STATS_LIST')
|
||||
self._server.remove_command_handler('STATS_FETCH')
|
||||
self._server.remove_command_handler('STATS_LIST')
|
||||
self._server.remove_command_handler('STATS_FETCH')
|
||||
|
||||
self._server = None
|
||||
|
||||
if self._tmp_dir is not None:
|
||||
shutil.rmtree(self._tmp_dir)
|
||||
self._tmp_dir = None
|
||||
|
||||
async def __aenter__(self):
|
||||
await self.setup()
|
||||
|
@ -473,7 +489,8 @@ class ProcessManager(object):
|
|||
mod = importlib.import_module(mod_name)
|
||||
cls = getattr(mod, cls_name)
|
||||
impl = cls(
|
||||
name=name, manager_address=manager_address, **kwargs)
|
||||
name=name, manager_address=manager_address, tmp_dir=self._tmp_dir,
|
||||
**kwargs)
|
||||
|
||||
rc = impl.main(child_connection)
|
||||
|
||||
|
@ -662,14 +679,15 @@ class ChildConnectionHandler(object):
|
|||
|
||||
|
||||
class ProcessBase(object):
|
||||
def __init__(self, *, name, manager, event_loop):
|
||||
def __init__(self, *, name, manager, event_loop, tmp_dir):
|
||||
self.name = name
|
||||
self.manager = manager
|
||||
self.event_loop = event_loop
|
||||
self.tmp_dir = tmp_dir
|
||||
self.server = None
|
||||
|
||||
async def setup(self):
|
||||
self.server = ipc.Server(self.event_loop, self.name)
|
||||
self.server = ipc.Server(self.event_loop, self.name, socket_dir=self.tmp_dir)
|
||||
await self.server.setup()
|
||||
|
||||
async def cleanup(self):
|
||||
|
|
|
@ -49,17 +49,6 @@ class Editor(object):
|
|||
|
||||
self.event_loop = asyncio.get_event_loop()
|
||||
self.manager = process_manager.ProcessManager(self.event_loop)
|
||||
self.manager.server.add_command_handler(
|
||||
'CREATE_PROJECT_PROCESS', self.handle_create_project_process)
|
||||
self.manager.server.add_command_handler(
|
||||
'CREATE_AUDIOPROC_PROCESS',
|
||||
self.handle_create_audioproc_process)
|
||||
self.manager.server.add_command_handler(
|
||||
'CREATE_NODE_DB_PROCESS',
|
||||
self.handle_create_node_db_process)
|
||||
self.manager.server.add_command_handler(
|
||||
'CREATE_INSTRUMENT_DB_PROCESS',
|
||||
self.handle_create_instrument_db_process)
|
||||
self.stop_event = asyncio.Event()
|
||||
self.returncode = 0
|
||||
|
||||
|
@ -86,6 +75,18 @@ class Editor(object):
|
|||
|
||||
async def run_async(self):
|
||||
async with self.manager:
|
||||
self.manager.server.add_command_handler(
|
||||
'CREATE_PROJECT_PROCESS', self.handle_create_project_process)
|
||||
self.manager.server.add_command_handler(
|
||||
'CREATE_AUDIOPROC_PROCESS',
|
||||
self.handle_create_audioproc_process)
|
||||
self.manager.server.add_command_handler(
|
||||
'CREATE_NODE_DB_PROCESS',
|
||||
self.handle_create_node_db_process)
|
||||
self.manager.server.add_command_handler(
|
||||
'CREATE_INSTRUMENT_DB_PROCESS',
|
||||
self.handle_create_instrument_db_process)
|
||||
|
||||
task = self.event_loop.create_task(self.launch_ui())
|
||||
task.add_done_callback(self.ui_closed)
|
||||
await self.stop_event.wait()
|
||||
|
|
|
@ -24,6 +24,7 @@ import asyncio
|
|||
|
||||
from noisidev import unittest
|
||||
from noisicaa.core import ipc
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
|
||||
from . import process
|
||||
from . import client
|
||||
|
@ -33,7 +34,7 @@ class TestClientImpl(object):
|
|||
def __init__(self, event_loop):
|
||||
super().__init__()
|
||||
self.event_loop = event_loop
|
||||
self.server = ipc.Server(self.event_loop, 'client')
|
||||
self.server = ipc.Server(self.event_loop, 'client', socket_dir=TEST_OPTS.TMP_DIR)
|
||||
|
||||
async def setup(self):
|
||||
await self.server.setup()
|
||||
|
@ -47,22 +48,32 @@ class TestClient(client.InstrumentDBClientMixin, TestClientImpl):
|
|||
|
||||
|
||||
class InstrumentDBClientTest(unittest.AsyncTestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.process = None
|
||||
self.process_task = None
|
||||
self.client = None
|
||||
|
||||
async def setup_testcase(self):
|
||||
self.process = process.InstrumentDBProcess(
|
||||
name='instrument_db', event_loop=self.loop, manager=None)
|
||||
name='instrument_db', event_loop=self.loop, manager=None, tmp_dir=TEST_OPTS.TMP_DIR)
|
||||
await self.process.setup()
|
||||
self.process_task = self.loop.create_task(
|
||||
self.process.run())
|
||||
self.process_task = self.loop.create_task(self.process.run())
|
||||
|
||||
self.client = TestClient(self.loop)
|
||||
await self.client.setup()
|
||||
await self.client.connect(self.process.server.address)
|
||||
|
||||
async def cleanup_testcase(self):
|
||||
await self.client.disconnect(shutdown=True)
|
||||
await self.client.cleanup()
|
||||
await asyncio.wait_for(self.process_task, None)
|
||||
await self.process.cleanup()
|
||||
if self.client is not None:
|
||||
await self.client.disconnect(shutdown=True)
|
||||
await self.client.cleanup()
|
||||
if self.process is not None:
|
||||
if self.process_task is not None:
|
||||
await self.process.shutdown()
|
||||
await asyncio.wait_for(self.process_task, None)
|
||||
await self.process.cleanup()
|
||||
|
||||
async def test_start_scan(self):
|
||||
await self.client.start_scan()
|
||||
|
|
|
@ -118,6 +118,13 @@ class InstrumentDBProcess(process_base.InstrumentDBProcessBase):
|
|||
logger.info("Shutting down...")
|
||||
self._shutdown_complete.set()
|
||||
|
||||
async def shutdown(self):
|
||||
logger.info("Shutdown received.")
|
||||
self._shutting_down.set()
|
||||
logger.info("Waiting for shutdown to complete...")
|
||||
await self._shutdown_complete.wait()
|
||||
logger.info("Shutdown complete.")
|
||||
|
||||
def get_session(self, session_id):
|
||||
try:
|
||||
return self.sessions[session_id]
|
||||
|
@ -157,11 +164,7 @@ class InstrumentDBProcess(process_base.InstrumentDBProcessBase):
|
|||
del self.sessions[session_id]
|
||||
|
||||
async def handle_shutdown(self):
|
||||
logger.info("Shutdown received.")
|
||||
self._shutting_down.set()
|
||||
logger.info("Waiting for shutdown to complete...")
|
||||
await self._shutdown_complete.wait()
|
||||
logger.info("Shutdown complete.")
|
||||
await self.shutdown()
|
||||
|
||||
async def handle_start_scan(self, session_id):
|
||||
self.get_session(session_id)
|
||||
|
|
|
@ -26,7 +26,6 @@ import functools
|
|||
import logging
|
||||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
import time
|
||||
import uuid
|
||||
|
||||
|
@ -220,7 +219,7 @@ class AudioProcClient(
|
|||
|
||||
|
||||
class Player(object):
|
||||
def __init__(self, project, callback_address, manager, event_loop):
|
||||
def __init__(self, *, project, callback_address, manager, event_loop, tmp_dir):
|
||||
self.project = project
|
||||
self.manager = manager
|
||||
self.callback_address = callback_address
|
||||
|
@ -230,7 +229,7 @@ class Player(object):
|
|||
self.__listeners = {}
|
||||
|
||||
self.id = uuid.uuid4().hex
|
||||
self.server = ipc.Server(self.event_loop, 'player')
|
||||
self.server = ipc.Server(self.event_loop, 'player', socket_dir=tmp_dir)
|
||||
|
||||
self.callback_stub = None
|
||||
|
||||
|
@ -241,8 +240,7 @@ class Player(object):
|
|||
self.audioproc_status_listener = None
|
||||
self.audioproc_player_state_listener = None
|
||||
self.audioproc_ready = None
|
||||
self.audiostream_address = os.path.join(
|
||||
tempfile.gettempdir(), 'audiostream.%s.pipe' % uuid.uuid4().hex)
|
||||
self.audiostream_address = os.path.join(tmp_dir, 'audiostream.%s.pipe' % uuid.uuid4().hex)
|
||||
|
||||
self.pending_pipeline_mutations = None
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ from noisicaa.bindings import lv2
|
|||
from noisicaa.core import ipc
|
||||
from noisicaa.node_db.private import db as node_db
|
||||
from noisidev import perf_stats
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
|
||||
from . import project
|
||||
from . import player
|
||||
|
@ -48,7 +49,7 @@ class TestAudioProcClientImpl(object):
|
|||
def __init__(self, event_loop, name):
|
||||
super().__init__()
|
||||
self.event_loop = event_loop
|
||||
self.server = ipc.Server(self.event_loop, name)
|
||||
self.server = ipc.Server(self.event_loop, name, socket_dir=TEST_OPTS.tmp_dir)
|
||||
|
||||
async def setup(self):
|
||||
await self.server.setup()
|
||||
|
|
|
@ -28,6 +28,7 @@ from noisidev import unittest
|
|||
from noisicaa import core
|
||||
from noisicaa import audioproc
|
||||
from noisicaa.core import ipc
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
|
||||
from . import project
|
||||
from . import player
|
||||
|
@ -82,13 +83,13 @@ class PlayerTest(unittest.AsyncTestCase):
|
|||
self.project = project.BaseProject()
|
||||
|
||||
self.player_status_calls = asyncio.Queue()
|
||||
self.callback_server = ipc.Server(self.loop, 'callback')
|
||||
self.callback_server = ipc.Server(self.loop, 'callback', socket_dir=TEST_OPTS.TMP_DIR)
|
||||
self.callback_server.add_command_handler(
|
||||
'PLAYER_STATUS',
|
||||
lambda player_id, kwargs: self.player_status_calls.put_nowait(kwargs))
|
||||
await self.callback_server.setup()
|
||||
|
||||
self.audioproc_server = ipc.Server(self.loop, 'audioproc')
|
||||
self.audioproc_server = ipc.Server(self.loop, 'audioproc', socket_dir=TEST_OPTS.TMP_DIR)
|
||||
await self.audioproc_server.setup()
|
||||
|
||||
self.mock_manager = mock.Mock()
|
||||
|
@ -108,7 +109,12 @@ class PlayerTest(unittest.AsyncTestCase):
|
|||
await self.callback_server.cleanup()
|
||||
|
||||
async def test_audio_stream_fails(self):
|
||||
p = player.Player(self.project, self.callback_server.address, self.mock_manager, self.loop)
|
||||
p = player.Player(
|
||||
project=self.project,
|
||||
callback_address=self.callback_server.address,
|
||||
manager=self.mock_manager,
|
||||
event_loop=self.loop,
|
||||
tmp_dir=TEST_OPTS.TMP_DIR)
|
||||
try:
|
||||
with mock.patch('noisicaa.music.player.AudioProcClient', MockAudioProcClient):
|
||||
await p.setup()
|
||||
|
|
|
@ -60,10 +60,10 @@ class ObjectProxy(core.ObjectBase):
|
|||
|
||||
|
||||
class ProjectClientBase(object):
|
||||
def __init__(self, event_loop):
|
||||
def __init__(self, event_loop, tmp_dir):
|
||||
super().__init__()
|
||||
self.event_loop = event_loop
|
||||
self.server = ipc.Server(self.event_loop, 'client')
|
||||
self.server = ipc.Server(self.event_loop, 'client', socket_dir=tmp_dir)
|
||||
|
||||
async def setup(self):
|
||||
await self.server.setup()
|
||||
|
|
|
@ -27,6 +27,7 @@ from noisidev import unittest
|
|||
from noisicaa import node_db
|
||||
from noisicaa.core import ipc
|
||||
from noisicaa.ui import model
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
|
||||
from . import project_process
|
||||
from . import project_client
|
||||
|
@ -36,7 +37,7 @@ class TestClientImpl():
|
|||
def __init__(self, event_loop):
|
||||
super().__init__()
|
||||
self.event_loop = event_loop
|
||||
self.server = ipc.Server(self.event_loop, 'client')
|
||||
self.server = ipc.Server(self.event_loop, 'client', socket_dir=TEST_OPTS.tmp_dir)
|
||||
|
||||
async def setup(self):
|
||||
await self.server.setup()
|
||||
|
|
|
@ -433,7 +433,12 @@ class ProjectProcess(core.ProcessBase):
|
|||
session = self.get_session(session_id)
|
||||
assert self.project is not None
|
||||
|
||||
p = player.Player(self.project, client_address, self.manager, self.event_loop)
|
||||
p = player.Player(
|
||||
project=self.project,
|
||||
callback_address=client_address,
|
||||
manager=self.manager,
|
||||
event_loop=self.event_loop,
|
||||
tmp_dir=self.tmp_dir)
|
||||
await p.setup()
|
||||
|
||||
session.add_player(p)
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
import asyncio
|
||||
|
||||
from noisidev import unittest
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
from noisicaa.core import ipc
|
||||
|
||||
from . import process
|
||||
|
@ -33,7 +34,7 @@ class TestClientImpl(object):
|
|||
def __init__(self, event_loop):
|
||||
super().__init__()
|
||||
self.event_loop = event_loop
|
||||
self.server = ipc.Server(self.event_loop, 'client')
|
||||
self.server = ipc.Server(self.event_loop, 'client', socket_dir=TEST_OPTS.TMP_DIR)
|
||||
|
||||
async def setup(self):
|
||||
await self.server.setup()
|
||||
|
@ -47,9 +48,16 @@ class TestClient(client.NodeDBClientMixin, TestClientImpl):
|
|||
|
||||
|
||||
class NodeDBClientTest(unittest.AsyncTestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.process = None
|
||||
self.process_task = None
|
||||
self.client = None
|
||||
|
||||
async def setup_testcase(self):
|
||||
self.process = process.NodeDBProcess(
|
||||
name='node_db', event_loop=self.loop, manager=None)
|
||||
name='node_db', event_loop=self.loop, manager=None, tmp_dir=TEST_OPTS.TMP_DIR)
|
||||
await self.process.setup()
|
||||
self.process_task = self.loop.create_task(
|
||||
self.process.run())
|
||||
|
@ -59,10 +67,14 @@ class NodeDBClientTest(unittest.AsyncTestCase):
|
|||
await self.client.connect(self.process.server.address)
|
||||
|
||||
async def cleanup_testcase(self):
|
||||
await self.client.disconnect(shutdown=True)
|
||||
await self.client.cleanup()
|
||||
await asyncio.wait_for(self.process_task, None)
|
||||
await self.process.cleanup()
|
||||
if self.client is not None:
|
||||
await self.client.disconnect(shutdown=True)
|
||||
await self.client.cleanup()
|
||||
if self.process is not None:
|
||||
if self.process_task is not None:
|
||||
await self.process.shutdown()
|
||||
await asyncio.wait_for(self.process_task, None)
|
||||
await self.process.cleanup()
|
||||
|
||||
async def test_start_scan(self):
|
||||
pass #await self.client.start_scan()
|
||||
|
|
|
@ -76,6 +76,13 @@ class NodeDBProcess(process_base.NodeDBProcessBase):
|
|||
logger.info("Shutting down...")
|
||||
self._shutdown_complete.set()
|
||||
|
||||
async def shutdown(self):
|
||||
logger.info("Shutdown received.")
|
||||
self._shutting_down.set()
|
||||
logger.info("Waiting for shutdown to complete...")
|
||||
await self._shutdown_complete.wait()
|
||||
logger.info("Shutdown complete.")
|
||||
|
||||
def get_session(self, session_id):
|
||||
try:
|
||||
return self.sessions[session_id]
|
||||
|
@ -105,11 +112,7 @@ class NodeDBProcess(process_base.NodeDBProcessBase):
|
|||
del self.sessions[session_id]
|
||||
|
||||
async def handle_shutdown(self):
|
||||
logger.info("Shutdown received.")
|
||||
self._shutting_down.set()
|
||||
logger.info("Waiting for shutdown to complete...")
|
||||
await self._shutdown_complete.wait()
|
||||
logger.info("Shutdown complete.")
|
||||
await self.shutdown()
|
||||
|
||||
async def handle_start_scan(self, session_id):
|
||||
self.get_session(session_id)
|
||||
|
|
|
@ -151,7 +151,7 @@ class BaseEditorApp(object):
|
|||
await self.createInstrumentDB()
|
||||
|
||||
self.project_registry = project_registry.ProjectRegistry(
|
||||
self.process.event_loop, self.process.manager, self.node_db)
|
||||
self.process.event_loop, self.process.tmp_dir, self.process.manager, self.node_db)
|
||||
|
||||
self.sequencer = self.createSequencer()
|
||||
|
||||
|
|
|
@ -46,9 +46,10 @@ class ProjectClient(music.ProjectClient):
|
|||
|
||||
|
||||
class Project(object):
|
||||
def __init__(self, path, event_loop, process_manager, node_db):
|
||||
def __init__(self, path, event_loop, tmp_dir, process_manager, node_db):
|
||||
self.path = path
|
||||
self.event_loop = event_loop
|
||||
self.tmp_dir = tmp_dir
|
||||
self.process_manager = process_manager
|
||||
self.node_db = node_db
|
||||
|
||||
|
@ -63,7 +64,9 @@ class Project(object):
|
|||
self.process_address = await self.process_manager.call(
|
||||
'CREATE_PROJECT_PROCESS', self.path)
|
||||
self.client = ProjectClient(
|
||||
event_loop=self.event_loop, node_db=self.node_db)
|
||||
event_loop=self.event_loop,
|
||||
tmp_dir=self.tmp_dir,
|
||||
node_db=self.node_db)
|
||||
self.client.cls_map.update(model.cls_map)
|
||||
await self.client.setup()
|
||||
await self.client.connect(self.process_address)
|
||||
|
@ -86,17 +89,18 @@ class Project(object):
|
|||
class ProjectRegistry(QtCore.QObject):
|
||||
projectListChanged = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, event_loop, process_manager, node_db):
|
||||
def __init__(self, event_loop, tmp_dir, process_manager, node_db):
|
||||
super().__init__()
|
||||
|
||||
self.event_loop = event_loop
|
||||
self.tmp_dir = tmp_dir
|
||||
self.process_manager = process_manager
|
||||
self.node_db = node_db
|
||||
self.projects = {}
|
||||
|
||||
async def open_project(self, path):
|
||||
project = Project(
|
||||
path, self.event_loop, self.process_manager, self.node_db)
|
||||
path, self.event_loop, self.tmp_dir, self.process_manager, self.node_db)
|
||||
await project.open()
|
||||
self.projects[path] = project
|
||||
self.projectListChanged.emit()
|
||||
|
@ -104,7 +108,7 @@ class ProjectRegistry(QtCore.QObject):
|
|||
|
||||
async def create_project(self, path):
|
||||
project = Project(
|
||||
path, self.event_loop, self.process_manager, self.node_db)
|
||||
path, self.event_loop, self.tmp_dir, self.process_manager, self.node_db)
|
||||
await project.create()
|
||||
self.projects[path] = project
|
||||
self.projectListChanged.emit()
|
||||
|
|
|
@ -35,6 +35,7 @@ from noisicaa import core
|
|||
from noisicaa import instrument_db
|
||||
from noisicaa import node_db
|
||||
from noisicaa.runtime_settings import RuntimeSettings
|
||||
from noisicaa.constants import TEST_OPTS
|
||||
from .editor_app import BaseEditorApp
|
||||
from . import model
|
||||
from . import selection_set
|
||||
|
@ -197,13 +198,20 @@ class UITest(unittest.AsyncTestCase):
|
|||
# than fighting with the garbage collection in pyqt5.
|
||||
app = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.node_db_process = None
|
||||
self.instrument_db_process = None
|
||||
self.process = None
|
||||
|
||||
async def setup_testcase(self):
|
||||
self.node_db_process = TestNodeDBProcess(
|
||||
name='node_db', event_loop=self.loop, manager=None)
|
||||
name='node_db', event_loop=self.loop, manager=None, tmp_dir=TEST_OPTS.TMP_DIR)
|
||||
await self.node_db_process.setup()
|
||||
|
||||
self.instrument_db_process = TestInstrumentDBProcess(
|
||||
name='instrument_db', event_loop=self.loop, manager=None)
|
||||
name='instrument_db', event_loop=self.loop, manager=None, tmp_dir=TEST_OPTS.TMP_DIR)
|
||||
await self.instrument_db_process.setup()
|
||||
|
||||
self.manager = mock.Mock()
|
||||
|
@ -218,7 +226,7 @@ class UITest(unittest.AsyncTestCase):
|
|||
self.manager.call.side_effect = mock_call
|
||||
|
||||
self.process = MockProcess(
|
||||
name='ui', event_loop=self.loop, manager=self.manager)
|
||||
name='ui', event_loop=self.loop, manager=self.manager, tmp_dir=TEST_OPTS.TMP_DIR)
|
||||
await self.process.setup()
|
||||
|
||||
if UITest.app is None:
|
||||
|
@ -244,11 +252,15 @@ class UITest(unittest.AsyncTestCase):
|
|||
self.commands = []
|
||||
|
||||
async def cleanup_testcase(self):
|
||||
await UITest.app.cleanup()
|
||||
UITest.app.process = None
|
||||
await self.process.cleanup()
|
||||
await self.instrument_db_process.cleanup()
|
||||
await self.node_db_process.cleanup()
|
||||
if UITest.app is not None and UITest.app.process is not None:
|
||||
await UITest.app.cleanup()
|
||||
UITest.app.process = None
|
||||
if self.process is not None:
|
||||
await self.process.cleanup()
|
||||
if self.instrument_db_process is not None:
|
||||
await self.instrument_db_process.cleanup()
|
||||
if self.node_db_process is not None:
|
||||
await self.node_db_process.cleanup()
|
||||
|
||||
_snapshot_numbers = {}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import os.path
|
|||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import textwrap
|
||||
import unittest
|
||||
|
||||
|
@ -127,6 +128,7 @@ def main(argv):
|
|||
parser.add_argument('--rebuild', nargs='?', type=bool_arg, const=True, default=True)
|
||||
parser.add_argument('--pedantic', nargs='?', type=bool_arg, const=True, default=False)
|
||||
parser.add_argument('--builtin-tests', nargs='?', type=bool_arg, const=True, default=True)
|
||||
parser.add_argument('--keep-temp', nargs='?', type=bool_arg, const=True, default=False)
|
||||
parser.add_argument('--playback-backend', type=str, default='null')
|
||||
args = parser.parse_args(argv[1:])
|
||||
|
||||
|
@ -201,6 +203,7 @@ def main(argv):
|
|||
constants.TEST_OPTS.WRITE_PERF_STATS = args.write_perf_stats
|
||||
constants.TEST_OPTS.ENABLE_PROFILER = args.profile
|
||||
constants.TEST_OPTS.PLAYBACK_BACKEND = args.playback_backend
|
||||
constants.TEST_OPTS.TMP_DIR = tempfile.mkdtemp(prefix='noisicaa-tests-')
|
||||
|
||||
from noisicaa import core
|
||||
core.init_pylogging()
|
||||
|
@ -276,6 +279,9 @@ def main(argv):
|
|||
runner = unittest.TextTestRunner(verbosity=2)
|
||||
result = runner.run(suite)
|
||||
|
||||
if not args.keep_temp:
|
||||
shutil.rmtree(constants.TEST_OPTS.TMP_DIR)
|
||||
|
||||
if args.coverage:
|
||||
cov.stop()
|
||||
cov_data = cov.get_data()
|
||||
|
|
Loading…
Reference in New Issue