Skip to content

Commit c0d76b3

Browse files
andy31415andreilitvinshaoltan-amazon
authored
Make tv casting tests use multithreading. (#34457)
* Make tv casting tests use multithreading. * Fix linter complaints * Use the send to program method instead of manual flush * return none on empty line, to not raise an empty exception. This will cause a timeout to be reported by the app * Fix import for linter * Actually allow json log decoding in our apps * Update scripts/tests/run_tv_casting_test.py Co-authored-by: Shao Ling Tan <161761051+shaoltan-amazon@users.noreply.github.com> * Update scripts/tests/linux/log_line_processing.py Co-authored-by: Shao Ling Tan <161761051+shaoltan-amazon@users.noreply.github.com> * Update scripts/tests/linux/log_line_processing.py Co-authored-by: Shao Ling Tan <161761051+shaoltan-amazon@users.noreply.github.com> * Update scripts/tests/linux/log_line_processing.py Co-authored-by: Shao Ling Tan <161761051+shaoltan-amazon@users.noreply.github.com> * Fix param * Also write empty stderr if they occur --------- Co-authored-by: Andrei Litvin <andreilitvin@google.com> Co-authored-by: Shao Ling Tan <161761051+shaoltan-amazon@users.noreply.github.com>
1 parent 985a9b0 commit c0d76b3

File tree

4 files changed

+377
-208
lines changed

4 files changed

+377
-208
lines changed

examples/tv-app/linux/args.gni

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ chip_enable_additional_data_advertising = true
3131
chip_enable_rotating_device_id = true
3232

3333
matter_enable_tracing_support = true
34+
matter_log_json_payload_hex = true
35+
matter_log_json_payload_decode_full = true
3436

3537
# Thread devices do not support WakeOnLan because their mac address is >48bit
3638
chip_enable_openthread = false

examples/tv-casting-app/linux/args.gni

+2
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ chip_max_discovered_ip_addresses = 20
3535
enable_rtti = true
3636

3737
matter_enable_tracing_support = true
38+
matter_log_json_payload_hex = true
39+
matter_log_json_payload_decode_full = true
+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import logging
16+
import queue
17+
import select
18+
import subprocess
19+
import threading
20+
from typing import List
21+
22+
23+
class ProcessOutputCapture:
24+
"""
25+
Captures stdout from a process and redirects such stdout to a given file.
26+
27+
The capture serves several purposes as opposed to just reading stdout:
28+
- as data is received, it will get written to a separate file
29+
- data is accumulated in memory for later processing (does not starve/block
30+
the process stdout)
31+
- provides read timeouts for incoming data
32+
33+
Use as part of a resource management block like:
34+
35+
with ProcessOutputCapture("test.sh", "logs.txt") as p:
36+
p.send_to_program("input\n")
37+
38+
while True:
39+
l = p.next_output_line(timeout_sec = 1)
40+
if not l:
41+
break
42+
"""
43+
44+
def __init__(self, command: List[str], output_path: str):
45+
# in/out/err are pipes
46+
self.command = command
47+
self.output_path = output_path
48+
self.output_lines = queue.Queue()
49+
self.process = None
50+
self.io_thread = None
51+
self.done = False
52+
53+
def _io_thread(self):
54+
"""Reads process lines and writes them to an output file.
55+
56+
It also sends the output lines to `self.output_lines` for later
57+
reading
58+
"""
59+
out_wait = select.poll()
60+
out_wait.register(self.process.stdout, select.POLLIN)
61+
62+
err_wait = select.poll()
63+
err_wait.register(self.process.stderr, select.POLLIN)
64+
65+
with open(self.output_path, "wt") as f:
66+
while not self.done:
67+
changes = out_wait.poll(0.1)
68+
if changes:
69+
out_line = self.process.stdout.readline()
70+
f.write(out_line)
71+
self.output_lines.put(out_line)
72+
73+
changes = err_wait.poll(0)
74+
if changes:
75+
err_line = self.process.stderr.readline()
76+
f.write(f"!!STDERR!! : {err_line}")
77+
78+
def __enter__(self):
79+
self.done = False
80+
self.process = subprocess.Popen(
81+
self.command,
82+
stdin=subprocess.PIPE,
83+
stdout=subprocess.PIPE,
84+
stderr=subprocess.PIPE,
85+
text=True,
86+
)
87+
self.io_thread = threading.Thread(target=self._io_thread)
88+
self.io_thread.start()
89+
return self
90+
91+
def __exit__(self, exception_type, exception_value, traceback):
92+
self.done = True
93+
if self.process:
94+
self.process.terminate()
95+
self.process.wait()
96+
97+
if self.io_thread:
98+
self.io_thread.join()
99+
100+
if exception_value:
101+
# When we fail because of an exception, report the entire log content
102+
logging.error(f"-------- START: LOG DUMP FOR {self.command!r} -----")
103+
with open(self.output_path, "rt") as f:
104+
for output_line in f.readlines():
105+
logging.error(output_line.strip())
106+
logging.error(f"-------- END: LOG DUMP FOR {self.command!r} -----")
107+
108+
def next_output_line(self, timeout_sec=None):
109+
"""Fetch an item from the output queue, potentially with a timeout."""
110+
try:
111+
return self.output_lines.get(timeout=timeout_sec)
112+
except queue.Empty:
113+
return None
114+
115+
def send_to_program(self, input_cmd):
116+
"""Sends the given input command string to the program.
117+
118+
NOTE: remember to append a `\n` for terminal applications
119+
"""
120+
self.process.stdin.write(input_cmd)
121+
self.process.stdin.flush()

0 commit comments

Comments
 (0)