Skip to content

Commit f18eaa2

Browse files
Testing on local branch for discovery between Linux tv-casting-app and tv-app.
1 parent 90732b2 commit f18eaa2

File tree

2 files changed

+228
-1
lines changed

2 files changed

+228
-1
lines changed

.github/workflows/examples-linux-tv-casting-app.yaml

+7-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ name: Test TV Casting Example
1717
on:
1818
push:
1919
branches-ignore:
20-
- 'dependabot/**'
20+
- "dependabot/**"
2121
pull_request:
2222
merge_group:
2323

@@ -63,6 +63,12 @@ jobs:
6363
./scripts/run_in_build_env.sh \
6464
"scripts/examples/gn_build_example.sh examples/tv-casting-app/linux/ out/tv-casting-app"
6565
66+
- name: Test casting from Linux tv-casting-app to Linux tv-app
67+
run: |
68+
./scripts/run_in_build_env.sh \
69+
"python3 ./scripts/tests/run_tv_casting_test.py test-casting"
70+
timeout-minutes: 1
71+
6672
- name: Uploading Size Reports
6773
uses: ./.github/actions/upload-size-reports
6874
if: ${{ !env.ACT }}

scripts/tests/run_tv_casting_test.py

+221
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#!/usr/bin/env -S python3 -B
2+
3+
# Copyright (c) 2024 Project CHIP Authors
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import os
18+
import subprocess
19+
import sys
20+
import time
21+
22+
import click
23+
24+
LINUX_TV_APP_LOGS = './scripts/tests/Linux-tv-app-logs.txt'
25+
LINUX_TV_CASTING_APP_LOGS = './scripts/tests/Linux-tv-casting-app-logs.txt'
26+
27+
RUN_INTERVAL = 2
28+
29+
VENDOR_ID = 65521
30+
PRODUCT_ID = 32769
31+
DEVICE_TYPE = 35
32+
33+
34+
# Dump the logs to the console in the case of an error.
35+
def dump_logs_to_console(log_file):
36+
if log_file == LINUX_TV_CASTING_APP_LOGS:
37+
print('Dumping Linux TV Casting App Logs to Console.')
38+
elif log_file == LINUX_TV_APP_LOGS:
39+
print('Dumping Linux TV App Logs to Console.')
40+
41+
with open(log_file, 'r') as file:
42+
logs = file.read()
43+
print(logs)
44+
45+
46+
# Remove the log files once the script is done running.
47+
def remove_log_file(log_file):
48+
if os.path.exists(log_file):
49+
os.remove(log_file)
50+
else:
51+
print("The file does not exist.")
52+
53+
54+
# Whenever a failure is discovered, we should print 'Discovery failed!',
55+
# dump the logs, clean up the log files, exit on error.
56+
def handle_discovery_failure():
57+
print('Discovery failed!\n')
58+
59+
dump_logs_to_console(LINUX_TV_CASTING_APP_LOGS)
60+
dump_logs_to_console(LINUX_TV_APP_LOGS)
61+
62+
remove_log_file(LINUX_TV_CASTING_APP_LOGS)
63+
remove_log_file(LINUX_TV_APP_LOGS)
64+
65+
sys.exit(1)
66+
67+
68+
# Helper function to extract the integer value from a string.
69+
def extract_value_from_string(line):
70+
value = line.split(":")[-1].strip().replace('\x1b[0m', '')
71+
value = int(value)
72+
73+
return value
74+
75+
76+
# Check if the discovered value matches the expected value.
77+
# Returns False if the value does not match the expected value, returns
78+
# True otherwise.
79+
def validate_value(expected_value, line, value_name):
80+
# Extract the integer value from the string
81+
value = extract_value_from_string(line)
82+
83+
# If the discovered value does not match the expected value,
84+
# print the error and handle the discovery failure.
85+
if value != expected_value:
86+
print(f'{value_name} does not match the expected value!')
87+
print(f'Expected {value_name}: {expected_value}')
88+
line = line.rstrip('\n')
89+
print(line)
90+
91+
# Return False if the value does not match the expected value.
92+
return False
93+
94+
# Return True if the value matches the expected value
95+
return True
96+
97+
98+
# Test if the Linux tv-casting-app is able to discover the Linux tv-app.
99+
# The Linux tv-casting-app and the tv-app will be run in separate processes.
100+
# Their corresponding output will be written to their respective log files.
101+
# The output of the tv-casting-app will be parsed in realtime for strings of
102+
# interest which will be printed to the console.
103+
def test_discovery_fn():
104+
105+
with open(LINUX_TV_APP_LOGS, 'w') as fd1, open(LINUX_TV_CASTING_APP_LOGS, 'w') as fd2:
106+
107+
# Run the Linux tv-app and write the output to file
108+
tv_app_rel_path = 'out/tv-app/chip-tv-app'
109+
tv_app_abs_path = os.path.abspath(tv_app_rel_path)
110+
tv_app_process = subprocess.Popen(tv_app_abs_path, stdout=fd1, stderr=subprocess.PIPE, text=True)
111+
112+
time.sleep(RUN_INTERVAL)
113+
114+
# Run the Linux tv-casting-app
115+
tv_casting_app_rel_path = 'out/tv-casting-app/chip-tv-casting-app'
116+
tv_casting_app_abs_path = os.path.abspath(tv_casting_app_rel_path)
117+
tv_casting_app_process = subprocess.Popen(
118+
tv_casting_app_abs_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
119+
120+
# Initialize variables
121+
continue_parsing = False
122+
valid_discovered_commissioner_str = ''
123+
valid_vendor_id_str = ''
124+
valid_product_id_str = ''
125+
valid_device_type_str = ''
126+
127+
# Read the output as we get it from the tv-casting-app process
128+
for line in tv_casting_app_process.stdout:
129+
# Write the line to the Linux tv-casting-app log file
130+
fd2.write(line)
131+
132+
# Fail fast if "No commissioner discovered" string found
133+
if "No commissioner discovered" in line:
134+
print(line)
135+
handle_discovery_failure()
136+
137+
# Look for 'Discovered Commissioner'
138+
if "Discovered Commissioner" in line:
139+
valid_discovered_commissioner_str = line
140+
141+
continue_parsing = True
142+
143+
valid_vendor_id = False
144+
valid_product_id = False
145+
valid_device_type = False
146+
147+
if continue_parsing:
148+
149+
# Check if the Vendor ID, Product ID, and Device Type match the expected values
150+
if "Vendor ID:" in line:
151+
152+
# If the value of the Vendor ID does not match the expected value, then
153+
# handle the discovery failure.
154+
valid_vendor_id = validate_value(VENDOR_ID, line, "Vendor ID")
155+
156+
if not valid_vendor_id:
157+
handle_discovery_failure()
158+
else:
159+
valid_vendor_id_str = line
160+
161+
elif "Product ID:" in line:
162+
163+
# If the value of Product ID does not match the expected value, then
164+
# handle the discovery failure.
165+
valid_product_id = validate_value(PRODUCT_ID, line, "Product ID")
166+
167+
if not valid_product_id:
168+
handle_discovery_failure()
169+
else:
170+
valid_product_id_str = line
171+
172+
elif "Device Type:" in line:
173+
174+
# If the value of Device Type does not match the expected value, then
175+
# handle the discovery failure.
176+
valid_device_type = validate_value(DEVICE_TYPE, line, "Device Type")
177+
178+
if not valid_device_type:
179+
handle_discovery_failure()
180+
else:
181+
valid_device_type_str = line
182+
183+
# Stop parsing if all values are valid.
184+
continue_parsing = False
185+
186+
if valid_vendor_id and valid_product_id and valid_device_type:
187+
print(valid_discovered_commissioner_str)
188+
print(valid_vendor_id_str)
189+
print(valid_product_id_str)
190+
print(valid_device_type_str)
191+
print('Discovery success!')
192+
193+
remove_log_file(LINUX_TV_CASTING_APP_LOGS)
194+
remove_log_file(LINUX_TV_APP_LOGS)
195+
196+
break
197+
198+
199+
# Tear down the processes.
200+
tv_app_process.terminate()
201+
tv_app_process.wait()
202+
203+
tv_casting_app_process.terminate()
204+
tv_casting_app_process.wait()
205+
206+
207+
@click.group()
208+
def main():
209+
pass
210+
211+
212+
@main.command('test-casting', help='Test casting from Linux tv-casting-app to Linux tv-app.')
213+
def test_casting():
214+
test_discovery_fn()
215+
216+
217+
if __name__ == '__main__':
218+
# Start with a clean slate by removing any previously cached entries.
219+
os.system('rm -f /tmp/chip_*')
220+
221+
main()

0 commit comments

Comments
 (0)