Skip to content
This repository was archived by the owner on Dec 27, 2023. It is now read-only.

Commit 5d9a984

Browse files
committed
Simplify sut_stdout and test_stdout events
Simplifed stdout events showing data coming from SUT during execution. With this patch we are also much faster to read from Qemu process stdout. Signed-off-by: Andrea Cervesato <[email protected]>
1 parent c005a50 commit 5d9a984

File tree

4 files changed

+45
-78
lines changed

4 files changed

+45
-78
lines changed

ltp/dispatcher.py

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -164,42 +164,21 @@ def exec_suites(self, suites: list, skip_tests: list = None) -> list:
164164
raise NotImplementedError()
165165

166166

167-
class StdoutChecker(IOBuffer):
167+
class RedirectTestStdout(IOBuffer):
168168
"""
169169
Check for test's stdout and raise an exception if Kernel panic occured.
170170
"""
171171

172172
def __init__(self, test: Test) -> None:
173-
self.stdout = ""
174173
self._test = test
175-
self._line = ""
174+
self.stdout = ""
176175

177176
def write(self, data: str) -> None:
178-
if len(data) == 1:
179-
self._line += data
180-
if data == "\n":
181-
ltp.events.fire(
182-
"test_stdout_line",
183-
self._test,
184-
self._line[:-1])
185-
self._line = ""
186-
else:
187-
lines = data.split('\n')
188-
for line in lines[:-1]:
189-
self._line += line
190-
ltp.events.fire("test_stdout_line", self._test, self._line)
191-
self._line = ""
192-
193-
self._line = lines[-1]
194-
195-
if data.endswith('\n') and self._line:
196-
ltp.events.fire("test_stdout_line", self._test, self._line)
197-
self._line = ""
198-
177+
ltp.events.fire("test_stdout", self._test, data)
199178
self.stdout += data
200179

201180

202-
class RedirectStdout(IOBuffer):
181+
class RedirectSUTStdout(IOBuffer):
203182
"""
204183
Redirect data from stdout to events.
205184
"""
@@ -211,7 +190,7 @@ def write(self, data: str) -> None:
211190
if not self._sut:
212191
return
213192

214-
ltp.events.fire("sut_stdout_line", self._sut.name, data)
193+
ltp.events.fire("sut_stdout", self._sut.name, data)
215194

216195

217196
class SerialDispatcher(Dispatcher):
@@ -313,7 +292,7 @@ def _reboot_sut(self, force: bool = False) -> None:
313292

314293
self._sut.ensure_communicate(
315294
timeout=3600,
316-
iobuffer=RedirectStdout(self._sut),
295+
iobuffer=RedirectSUTStdout(self._sut),
317296
force=force)
318297

319298
self._logger.info("SUT rebooted")
@@ -365,12 +344,12 @@ def _run_test(self, test: Test) -> TestResults:
365344
timed_out = False
366345
reboot = False
367346

368-
checker = StdoutChecker(test)
347+
buffer = RedirectTestStdout(test)
369348
try:
370349
test_data = self._sut.run_command(
371350
cmd,
372351
timeout=self._test_timeout,
373-
iobuffer=checker)
352+
iobuffer=buffer)
374353
except SUTTimeoutError:
375354
timed_out = True
376355
try:
@@ -405,7 +384,7 @@ def _run_test(self, test: Test) -> TestResults:
405384
test_data = {
406385
"name": test.name,
407386
"command": test.command,
408-
"stdout": checker.stdout,
387+
"stdout": buffer.stdout,
409388
"returncode": -1,
410389
"exec_time": self._test_timeout,
411390
}

ltp/qemu.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def __init__(self) -> None:
5656
self._serial_type = None
5757
self._qemu_cmd = None
5858
self._opts = None
59+
self._last_read = ""
5960

6061
@staticmethod
6162
def _generate_string(length: int = 10) -> str:
@@ -263,28 +264,41 @@ def _wait_for(
263264
if not self.is_running:
264265
return None
265266

266-
stdout = ""
267+
stdout = self._last_read
267268
panic = False
269+
found = False
268270

269271
with Timeout(timeout) as timer:
270-
while not stdout.endswith(message):
272+
while not found:
271273
events = self._poller.poll(0.1)
272274

273-
if not events and self._stop:
274-
break
275+
# stop or panic when no events are available,
276+
# so we collect all stdout before exit
277+
if not events:
278+
if self._stop:
279+
break
275280

276-
if not events and panic:
277-
raise KernelPanicError()
281+
if panic:
282+
raise KernelPanicError()
278283

279284
for fdesc, _ in events:
280285
if fdesc != self._proc.stdout.fileno():
281286
continue
282287

283-
data = self._read_stdout(1, iobuffer)
288+
data = self._read_stdout(1024, iobuffer)
284289
if data:
285290
stdout += data
286291

287-
if stdout.endswith("Kernel panic"):
292+
# search for message inside stdout
293+
message_pos = stdout.find(message)
294+
if message_pos != -1:
295+
self._last_read = stdout[message_pos + len(message):]
296+
found = True
297+
break
298+
299+
# turn on panic flag, so we rise it when all the
300+
# stdout has been collected
301+
if "Kernel panic" in stdout:
288302
panic = True
289303

290304
timer.check(

ltp/session.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class SessionError(LTPException):
2525
"""
2626

2727

28-
class Printer(IOBuffer):
28+
class RedirectStdout(IOBuffer):
2929
"""
3030
Redirect data from stdout to events.
3131
"""
@@ -38,7 +38,7 @@ def write(self, data: str) -> None:
3838
if self._is_cmd:
3939
ltp.events.fire("run_cmd_stdout", data)
4040
else:
41-
ltp.events.fire("sut_stdout_line", self._sut.name, data)
41+
ltp.events.fire("sut_stdout", self._sut.name, data)
4242

4343

4444
class Session:
@@ -150,7 +150,7 @@ def _start_sut(self) -> None:
150150

151151
self._sut.ensure_communicate(
152152
timeout=3600,
153-
iobuffer=Printer(self._sut, False))
153+
iobuffer=RedirectStdout(self._sut, False))
154154

155155
def _stop_sut(self, timeout: float = 30) -> None:
156156
"""
@@ -164,11 +164,11 @@ def _stop_sut(self, timeout: float = 30) -> None:
164164
if self._sut.is_running:
165165
self._sut.stop(
166166
timeout=timeout,
167-
iobuffer=Printer(self._sut, False))
167+
iobuffer=RedirectStdout(self._sut, False))
168168
else:
169169
self._sut.force_stop(
170170
timeout=timeout,
171-
iobuffer=Printer(self._sut, False))
171+
iobuffer=RedirectStdout(self._sut, False))
172172

173173
def _stop_all(self, timeout: float = 30) -> None:
174174
"""
@@ -227,7 +227,7 @@ def run_single(
227227
ret = self._sut.run_command(
228228
command,
229229
timeout=self._exec_timeout,
230-
iobuffer=Printer(self._sut, True))
230+
iobuffer=RedirectStdout(self._sut, True))
231231

232232
ltp.events.fire(
233233
"run_cmd_stop",

ltp/ui.py

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@
1313
from ltp.results import TestResults
1414
from ltp.results import SuiteResults
1515

16+
1617
# pylint: disable=too-many-public-methods
1718
# pylint: disable=missing-function-docstring
1819
# pylint: disable=unused-argument
19-
20-
2120
class ConsoleUserInterface:
2221
"""
2322
Console based user interface.
@@ -32,7 +31,6 @@ class ConsoleUserInterface:
3231

3332
def __init__(self, no_colors: bool = False) -> None:
3433
self._no_colors = no_colors
35-
self._line = ""
3634
self._tmpdir = ""
3735

3836
ltp.events.register("session_started", self.session_started)
@@ -81,30 +79,6 @@ def _user_friendly_duration(duration: float) -> str:
8179

8280
return uf_time
8381

84-
def _print_stdout(self, data: str) -> None:
85-
"""
86-
Print stdout coming from command run or test.
87-
"""
88-
if len(data) == 1:
89-
self._line += data
90-
if data == "\n":
91-
self._print(self._line, end='')
92-
self._line = ""
93-
else:
94-
lines = data.splitlines(True)
95-
if len(lines) > 0:
96-
for line in lines[:-1]:
97-
self._line += line
98-
99-
self._print(self._line, end='')
100-
self._line = ""
101-
102-
self._line = lines[-1]
103-
104-
if data.endswith('\n') and self._line:
105-
self._print(self._line, end='')
106-
self._line = ""
107-
10882
def session_started(self, tmpdir: str) -> None:
10983
uname = platform.uname()
11084
message = "Host information\n\n"
@@ -135,7 +109,7 @@ def run_cmd_start(self, cmd: str) -> None:
135109
self._print(f"{cmd}", color=self.CYAN)
136110

137111
def run_cmd_stdout(self, data: str) -> None:
138-
self._print_stdout(data)
112+
self._print(data, end='')
139113

140114
def run_cmd_stop(self, command: str, stdout: str, returncode: int) -> None:
141115
self._print(f"\nExit code: {returncode}\n")
@@ -273,15 +247,15 @@ def __init__(self, no_colors: bool = False) -> None:
273247

274248
self._timed_out = False
275249

276-
ltp.events.register("sut_stdout_line", self.sut_stdout_line)
250+
ltp.events.register("sut_stdout", self.sut_stdout)
277251
ltp.events.register("kernel_tainted", self.kernel_tainted)
278252
ltp.events.register("test_timed_out", self.test_timed_out)
279253
ltp.events.register("test_started", self.test_started)
280254
ltp.events.register("test_completed", self.test_completed)
281-
ltp.events.register("test_stdout_line", self.test_stdout_line)
255+
ltp.events.register("test_stdout", self.test_stdout)
282256

283-
def sut_stdout_line(self, _: str, data: str) -> None:
284-
self._print_stdout(data)
257+
def sut_stdout(self, _: str, data: str) -> None:
258+
self._print(data, end='')
285259

286260
def kernel_tainted(self, message: str) -> None:
287261
self._print(f"Tained kernel: {message}", color=self.YELLOW)
@@ -313,10 +287,10 @@ def test_completed(self, results: TestResults) -> None:
313287
uf_time = self._user_friendly_duration(results.exec_time)
314288
self._print(f"\nDuration: {uf_time}\n")
315289

316-
def test_stdout_line(self, _: Test, line: str) -> None:
290+
def test_stdout(self, _: Test, line: str) -> None:
317291
col = ""
318292

319293
if "Kernel panic" in line:
320294
col = self.RED
321295

322-
self._print(line, color=col)
296+
self._print(line, color=col, end='')

0 commit comments

Comments
 (0)