Skip to content

Commit 373874b

Browse files
tests/conftest: move common Exporter functionality into generic LabgridComponent
Most functionality of this class is not exporter- or coordinator-specific, so move the common parts into a common class. Both Exporter (and a future) Coordinator class will inherhit it. Signed-off-by: Bastian Krause <[email protected]>
1 parent cb9ecde commit 373874b

File tree

1 file changed

+55
-36
lines changed

1 file changed

+55
-36
lines changed

tests/conftest.py

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,6 @@ def curses_init():
2121
except ModuleNotFoundError:
2222
logging.warning("curses module not found, not setting up a default terminal – tests may fail")
2323

24-
def keep_reading(spawn):
25-
"The output from background processes must be read to avoid blocking them."
26-
while spawn.isalive():
27-
try:
28-
data = spawn.read_nonblocking(size=1024, timeout=0.1)
29-
if not data:
30-
return
31-
except pexpect.TIMEOUT:
32-
continue
33-
except pexpect.EOF:
34-
return
35-
except OSError:
36-
return
37-
3824

3925
class Prefixer:
4026
def __init__(self, wrapped, prefix):
@@ -60,40 +46,51 @@ def __getattr__(self, name):
6046
return getattr(self.__wrapped, name)
6147

6248

63-
class Exporter:
64-
def __init__(self, config, cwd):
49+
class LabgridComponent:
50+
def __init__(self, cwd):
6551
self.cwd = str(cwd)
66-
self.config = config
6752
self.spawn = None
6853
self.reader = None
6954

70-
def start(self):
71-
assert self.spawn is None
72-
assert self.reader is None
55+
def stop(self):
56+
logging.info("stopping {self.__class__.__name__} pid=%s", self.spawn.pid)
57+
58+
# let coverage write its data:
59+
# https://coverage.readthedocs.io/en/latest/subprocess.html#process-termination
60+
self.spawn.kill(SIGTERM)
61+
if not self.spawn.closed:
62+
self.spawn.expect(pexpect.EOF)
63+
self.spawn.wait()
64+
assert not self.spawn.isalive()
7365

74-
self.spawn = pexpect.spawn(
75-
f'{sys.executable} -m labgrid.remote.exporter --name testhost {self.config}',
76-
logfile=Prefixer(sys.stdout.buffer, 'exporter'),
77-
cwd=self.cwd)
78-
try:
79-
self.spawn.expect('exporter name: testhost')
80-
self.spawn.expect('connected to exporter')
81-
except Exception as e:
82-
raise Exception(f"exporter startup failed with {self.spawn.before}") from e
66+
self.spawn = None
67+
self.stop_reader()
68+
69+
@staticmethod
70+
def keep_reading(spawn):
71+
"The output from background processes must be read to avoid blocking them."
72+
while spawn.isalive():
73+
try:
74+
data = spawn.read_nonblocking(size=1024, timeout=0.1)
75+
if not data:
76+
return
77+
except pexpect.TIMEOUT:
78+
continue
79+
except pexpect.EOF:
80+
return
81+
except OSError:
82+
return
8383

84+
def start_reader(self):
8485
self.reader = threading.Thread(
85-
target=keep_reading,
86-
name=f'exporter-reader-{self.pid}',
86+
target=LabgridComponent.keep_reading,
87+
name=f'{self.__class__.__name__}-reader-{self.pid}',
8788
args=(self.spawn,), daemon=True)
8889
self.reader.start()
8990

90-
def stop(self):
91-
logging.info("stopping exporter pid=%s", self.spawn.pid)
92-
self.spawn.close(force=True)
93-
assert not self.spawn.isalive()
91+
def stop_reader(self):
9492
self.reader.join()
9593

96-
self.spawn = None
9794
self.reader = None
9895

9996
def isalive(self):
@@ -108,6 +105,28 @@ def pid(self):
108105
return self.spawn.pid
109106

110107

108+
class Exporter(LabgridComponent):
109+
def __init__(self, config, cwd):
110+
super().__init__(cwd)
111+
self.config = config
112+
113+
def start(self):
114+
assert self.spawn is None
115+
assert self.reader is None
116+
117+
self.spawn = pexpect.spawn(
118+
f'labgrid-exporter --name testhost {self.config}',
119+
logfile=Prefixer(sys.stdout.buffer, 'exporter'),
120+
cwd=self.cwd)
121+
try:
122+
self.spawn.expect('exporter name: testhost')
123+
self.spawn.expect('connected to exporter')
124+
except Exception as e:
125+
raise Exception(f"exporter startup failed with {self.spawn.before}") from e
126+
127+
self.start_reader()
128+
129+
111130
@pytest.fixture(scope='function')
112131
def target():
113132
return Target('Test')

0 commit comments

Comments
 (0)