forked from M-Labs/artiq
hardware_testbench: use plain subprocess to start controllers
This commit is contained in:
parent
1b7020dff3
commit
982fbb0670
|
@ -5,14 +5,14 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import logging
|
import logging
|
||||||
import asyncio
|
import subprocess
|
||||||
import threading
|
import shlex
|
||||||
|
import time
|
||||||
|
|
||||||
from artiq.master.databases import DeviceDB, DatasetDB
|
from artiq.master.databases import DeviceDB, DatasetDB
|
||||||
from artiq.master.worker_db import DeviceManager, DatasetManager
|
from artiq.master.worker_db import DeviceManager, DatasetManager
|
||||||
from artiq.coredevice.core import CompileError
|
from artiq.coredevice.core import CompileError
|
||||||
from artiq.frontend.artiq_run import DummyScheduler
|
from artiq.frontend.artiq_run import DummyScheduler
|
||||||
from artiq.devices.ctlmgr import Controllers
|
|
||||||
|
|
||||||
|
|
||||||
artiq_root = os.getenv("ARTIQ_ROOT")
|
artiq_root = os.getenv("ARTIQ_ROOT")
|
||||||
|
@ -21,75 +21,38 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@unittest.skipUnless(artiq_root, "no ARTIQ_ROOT")
|
@unittest.skipUnless(artiq_root, "no ARTIQ_ROOT")
|
||||||
class ControllerCase(unittest.TestCase):
|
class ControllerCase(unittest.TestCase):
|
||||||
host_filter = "::1"
|
|
||||||
timeout = 2
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
if os.name == "nt":
|
|
||||||
self.loop = asyncio.ProactorEventLoop()
|
|
||||||
else:
|
|
||||||
self.loop = asyncio.new_event_loop()
|
|
||||||
asyncio.set_event_loop(self.loop)
|
|
||||||
self.addCleanup(self.loop.close)
|
|
||||||
|
|
||||||
self.loop_thread = threading.Thread(target=self.loop.run_forever)
|
|
||||||
self.addCleanup(self.loop_thread.join)
|
|
||||||
self.addCleanup(self.loop.call_soon_threadsafe, self.loop.stop)
|
|
||||||
|
|
||||||
self.controllers = Controllers()
|
|
||||||
self.controllers.host_filter = self.host_filter
|
|
||||||
self.addCleanup(self._stop_controllers)
|
|
||||||
|
|
||||||
self.device_db = DeviceDB(os.path.join(artiq_root, "device_db.pyon"))
|
self.device_db = DeviceDB(os.path.join(artiq_root, "device_db.pyon"))
|
||||||
self.device_mgr = DeviceManager(self.device_db)
|
self.device_mgr = DeviceManager(self.device_db)
|
||||||
self.addCleanup(self.device_mgr.close_devices)
|
self.addCleanup(self.device_mgr.close_devices)
|
||||||
|
self.controllers = {}
|
||||||
|
|
||||||
self.loop_thread.start()
|
def tearDown(self):
|
||||||
|
self.stop_controllers()
|
||||||
|
|
||||||
def _stop_controllers(self):
|
def start_controller(self, name, sleep=1):
|
||||||
fut = asyncio.run_coroutine_threadsafe(self.controllers.shutdown(),
|
try:
|
||||||
self.loop)
|
entry = self.device_db.get(name)
|
||||||
fut.result()
|
except KeyError:
|
||||||
|
raise unittest.SkipTest(
|
||||||
|
"controller `{}` not found".format(name))
|
||||||
|
entry["command"] = entry["command"].format(
|
||||||
|
name=name, bind=entry["host"], port=entry["port"])
|
||||||
|
proc = subprocess.Popen(shlex.split(entry["command"]))
|
||||||
|
self.controllers[name] = entry, proc
|
||||||
|
time.sleep(sleep)
|
||||||
|
|
||||||
async def _start(self, *names):
|
def stop_controllers(self):
|
||||||
print("FOOO started")
|
for entry, proc in self.controllers.values():
|
||||||
l = asyncio.get_event_loop_policy()
|
proc.terminate()
|
||||||
l = l.get_event_loop()
|
for name in list(self.controllers):
|
||||||
print("FOOO started")
|
entry, proc = self.controllers[name]
|
||||||
|
|
||||||
|
|
||||||
for name in names:
|
|
||||||
try:
|
try:
|
||||||
self.controllers[name] = self.device_db.get(name)
|
proc.wait(entry.get("term_timeout"))
|
||||||
except KeyError:
|
except TimeoutError:
|
||||||
raise unittest.SkipTest(
|
proc.kill()
|
||||||
"controller `{}` not found".format(name))
|
proc.wait(entry.get("term_timeout"))
|
||||||
await self.controllers.queue.join()
|
del self.controllers[name]
|
||||||
await asyncio.wait([self._wait_for_ping(name)
|
|
||||||
for name in names])
|
|
||||||
|
|
||||||
async def _wait_for_ping(self, name, retries=5):
|
|
||||||
t = self.timeout
|
|
||||||
dt = t/retries
|
|
||||||
while t > 0:
|
|
||||||
try:
|
|
||||||
ok = await asyncio.wait_for(
|
|
||||||
self.controllers.active[name].call("ping"), dt)
|
|
||||||
if not ok:
|
|
||||||
raise ValueError("unexcepted ping() response from "
|
|
||||||
"controller `{}`: `{}`".format(name, ok))
|
|
||||||
return ok
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
t -= dt
|
|
||||||
except (ConnectionAbortedError, ConnectionError,
|
|
||||||
ConnectionRefusedError, ConnectionResetError):
|
|
||||||
await asyncio.sleep(dt)
|
|
||||||
t -= dt
|
|
||||||
raise asyncio.TimeoutError
|
|
||||||
|
|
||||||
def start_controllers(self, *names):
|
|
||||||
fut = asyncio.run_coroutine_threadsafe(self._start(*names), self.loop)
|
|
||||||
fut.result()
|
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(artiq_root, "no ARTIQ_ROOT")
|
@unittest.skipUnless(artiq_root, "no ARTIQ_ROOT")
|
||||||
|
|
|
@ -20,7 +20,7 @@ class GenericLdaTest:
|
||||||
class TestLda(ControllerCase, GenericLdaTest):
|
class TestLda(ControllerCase, GenericLdaTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
ControllerCase.setUp(self)
|
ControllerCase.setUp(self)
|
||||||
self.start_controllers("lda")
|
self.start_controller("lda")
|
||||||
self.cont = self.device_mgr.get("lda")
|
self.cont = self.device_mgr.get("lda")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from artiq.devices.novatech409b.driver import Novatech409B
|
from artiq.devices.novatech409b.driver import Novatech409B
|
||||||
from artiq.test.hardware_testbench import ControllerCase, with_controllers
|
from artiq.test.hardware_testbench import ControllerCase
|
||||||
|
|
||||||
|
|
||||||
class GenericNovatech409BTest:
|
class GenericNovatech409BTest:
|
||||||
|
@ -21,10 +21,10 @@ class GenericNovatech409BTest:
|
||||||
|
|
||||||
|
|
||||||
class TestNovatech409B(GenericNovatech409BTest, ControllerCase):
|
class TestNovatech409B(GenericNovatech409BTest, ControllerCase):
|
||||||
@with_controllers("novatech409b")
|
def setUp(self):
|
||||||
def test_parameters_readback(self):
|
ControllerCase.setUp(self)
|
||||||
|
self.start_controller("novatech409b")
|
||||||
self.driver = self.device_mgr.get("novatech409b")
|
self.driver = self.device_mgr.get("novatech409b")
|
||||||
GenericNovatech409BTest.test_parameters_readback(self)
|
|
||||||
|
|
||||||
|
|
||||||
class TestNovatech409BSim(GenericNovatech409BTest, unittest.TestCase):
|
class TestNovatech409BSim(GenericNovatech409BTest, unittest.TestCase):
|
||||||
|
|
|
@ -3,7 +3,7 @@ import time
|
||||||
|
|
||||||
from artiq.devices.thorlabs_tcube.driver import Tdc, Tpz, TdcSim, TpzSim
|
from artiq.devices.thorlabs_tcube.driver import Tdc, Tpz, TdcSim, TpzSim
|
||||||
from artiq.language.units import V
|
from artiq.language.units import V
|
||||||
from artiq.test.hardware_testbench import get_from_ddb
|
from artiq.test.hardware_testbench import ControllerCase
|
||||||
|
|
||||||
|
|
||||||
class GenericTdcTest:
|
class GenericTdcTest:
|
||||||
|
@ -131,10 +131,11 @@ class GenericTpzTest:
|
||||||
self.assertEqual(test_vector, self.cont.get_tpz_io_settings())
|
self.assertEqual(test_vector, self.cont.get_tpz_io_settings())
|
||||||
|
|
||||||
|
|
||||||
class TestTdc(unittest.TestCase, GenericTdcTest):
|
class TestTdc(ControllerCase, GenericTdcTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
tdc_serial = get_from_ddb("tdc", "device")
|
ControllerCase.setUp(self)
|
||||||
self.cont = Tdc(serial_dev=tdc_serial)
|
self.start_controller("tdc")
|
||||||
|
self.cont = self.device_mgr.get("tdc")
|
||||||
|
|
||||||
|
|
||||||
class TestTdcSim(unittest.TestCase, GenericTdcTest):
|
class TestTdcSim(unittest.TestCase, GenericTdcTest):
|
||||||
|
@ -142,10 +143,11 @@ class TestTdcSim(unittest.TestCase, GenericTdcTest):
|
||||||
self.cont = TdcSim()
|
self.cont = TdcSim()
|
||||||
|
|
||||||
|
|
||||||
class TestTpz(unittest.TestCase, GenericTpzTest):
|
class TestTpz(ControllerCase, GenericTpzTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
tpz_serial = get_from_ddb("tpz", "device")
|
ControllerCase.setUp(self)
|
||||||
self.cont = Tpz(serial_dev=tpz_serial)
|
self.start_controller("tpz")
|
||||||
|
self.cont = self.device_mgr.get("tpz")
|
||||||
|
|
||||||
|
|
||||||
class TestTpzSim(unittest.TestCase, GenericTpzTest):
|
class TestTpzSim(unittest.TestCase, GenericTpzTest):
|
||||||
|
|
Loading…
Reference in New Issue