Skip to content

Commit 329851a

Browse files
[Linux] Add test logic to verify the subscription state in the Linux tv-casting-app.
1 parent 550b1c1 commit 329851a

File tree

1 file changed

+86
-6
lines changed

1 file changed

+86
-6
lines changed

scripts/tests/run_tv_casting_test.py

+86-6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
# The maximum amount of time to test that the launchURL is sent from the Linux tv-casting-app and received on the tv-app before timeout.
3737
TEST_LAUNCHURL_MAX_WAIT_SEC = 10
3838

39+
# The maximum amount of time to verify the subscription state in the Linux tv-casting-app output before timeout.
40+
VERIFY_SUBSCRIPTION_STATE_MAX_WAIT_SEC = 10
41+
3942
# File names of logs for the Linux tv-casting-app and the Linux tv-app.
4043
LINUX_TV_APP_LOGS = 'Linux-tv-app-logs.txt'
4144
LINUX_TV_CASTING_APP_LOGS = 'Linux-tv-casting-app-logs.txt'
@@ -46,6 +49,10 @@
4649
PRODUCT_ID = 0x8001 # Test product id
4750
DEVICE_TYPE_CASTING_VIDEO_PLAYER = 0x23 # Device type library 10.3: Casting Video Player
4851

52+
# Values to verify the subscription state against from the `ReportDataMessage` in the Linux tv-casting-app output.
53+
CLUSTER_MEDIA_PLAYBACK = '0x506' # Application Cluster Spec 6.10.3 Cluster ID: Media Playback
54+
ATTRIBUTE_CURRENT_PLAYBACK_STATE = '0x0000_0000' # Application Cluster Spec 6.10.6 Attribute ID: Current State of Playback
55+
4956

5057
class ProcessManager:
5158
"""A context manager for managing subprocesses.
@@ -96,13 +103,19 @@ def extract_value_from_string(line: str) -> str:
96103
97104
The string is expected to be in the following format as it is received
98105
from the Linux tv-casting-app output:
106+
\x1b[0;34m[1715206773402] [20056:2842184] [DMG] Cluster = 0x506,\x1b[0m
107+
The substring to be extracted here is '0x506'.
108+
Or:
99109
\x1b[0;34m[1713741926895] [7276:9521344] [DIS] Vendor ID: 65521\x1b[0m
100110
The integer value to be extracted here is 65521.
101111
Or:
102112
\x1b[0;34m[1714583616179] [7029:2386956] [SVR] device Name: Test TV casting app\x1b[0m
103113
The substring to be extracted here is 'Test TV casting app'.
104114
"""
105-
value = line.split(':')[-1].strip().replace('\x1b[0m', '')
115+
if '=' in line:
116+
value = line.split('=')[-1].strip().replace(',\x1b[0m', '')
117+
else:
118+
value = line.split(':')[-1].strip().replace('\x1b[0m', '')
106119

107120
return value
108121

@@ -221,7 +234,7 @@ def validate_identification_declaration_message_on_tv_app(tv_app_info: Tuple[sub
221234
linux_tv_app_log_file.flush()
222235

223236
if 'Identification Declaration Start' in tv_app_line:
224-
logging.info('"Identification Declaration" block from the Linux tv-app output:')
237+
logging.info('Found the `Identification Declaration` block in the Linux tv-app output:')
225238
logging.info(tv_app_line.rstrip('\n'))
226239
parsing_identification_block = True
227240
elif parsing_identification_block:
@@ -310,6 +323,56 @@ def validate_commissioning_success(tv_casting_app_info: Tuple[subprocess.Popen,
310323
return True
311324

312325

326+
def parse_tv_casting_app_for_report_data_msg(tv_casting_app_info: Tuple[subprocess.Popen, TextIO], log_paths: List[str]):
327+
"""Parse the Linux tv-casting-app for `ReportDataMessage` block and return the first message block with valid `Cluster` and `Attribute` values."""
328+
tv_casting_app_process, linux_tv_casting_app_log_file = tv_casting_app_info
329+
330+
continue_parsing = False
331+
report_data_message = []
332+
333+
start_wait_time = time.time()
334+
335+
while True:
336+
# Check if we exceeded the maximum wait time to parse the Linux tv-casting-app output for `ReportDataMessage` block.
337+
if time.time() - start_wait_time > VERIFY_SUBSCRIPTION_STATE_MAX_WAIT_SEC:
338+
logging.error(
339+
'The relevant `ReportDataMessage` block was not found in the Linux tv-casting-app process within the timeout.')
340+
report_data_message.clear()
341+
return report_data_message
342+
343+
tv_casting_line = tv_casting_app_process.stdout.readline()
344+
345+
if tv_casting_line:
346+
linux_tv_casting_app_log_file.write(tv_casting_line)
347+
linux_tv_casting_app_log_file.flush()
348+
349+
if 'ReportDataMessage =' in tv_casting_line:
350+
report_data_message.append(tv_casting_line.rstrip('\n'))
351+
continue_parsing = True
352+
elif continue_parsing:
353+
report_data_message.append(tv_casting_line.rstrip('\n'))
354+
355+
if 'Cluster =' in tv_casting_line:
356+
cluster_value = extract_value_from_string(tv_casting_line)
357+
if cluster_value != CLUSTER_MEDIA_PLAYBACK:
358+
report_data_message.clear()
359+
continue_parsing = False
360+
361+
elif 'Attribute =' in tv_casting_line:
362+
attribute_value = extract_value_from_string(tv_casting_line)
363+
if attribute_value != ATTRIBUTE_CURRENT_PLAYBACK_STATE:
364+
report_data_message.clear()
365+
continue_parsing = False
366+
367+
elif 'InteractionModelRevision' in tv_casting_line:
368+
# Capture the closing brace `}` of the `ReportDataMessage` block.
369+
tv_casting_line = tv_casting_app_process.stdout.readline()
370+
linux_tv_casting_app_log_file.write(tv_casting_line)
371+
linux_tv_casting_app_log_file.flush()
372+
report_data_message.append(tv_casting_line.rstrip('\n'))
373+
return report_data_message
374+
375+
313376
def parse_tv_app_output_for_launchUrl_msg_success(tv_app_info: Tuple[subprocess.Popen, TextIO], log_paths: List[str]):
314377
"""Parse the Linux tv-app output for the relevant string indicating that the launchUrl was received."""
315378

@@ -359,7 +422,7 @@ def parse_tv_casting_app_output_for_launchUrl_msg_success(tv_casting_app_info: T
359422
linux_tv_casting_app_log_file.flush()
360423

361424
if 'InvokeResponseMessage =' in tv_casting_line:
362-
logging.info('Found the InvokeResponseMessage block in the Linux tv-casting-app output:')
425+
logging.info('Found the `InvokeResponseMessage` block in the Linux tv-casting-app output:')
363426
logging.info(tv_casting_line.rstrip('\n'))
364427
continue_parsing_invoke_response_msg_block = True
365428

@@ -415,7 +478,7 @@ def test_discovery_fn(tv_casting_app_info: Tuple[subprocess.Popen, TextIO], log_
415478

416479
# A valid commissioner has VENDOR_ID, PRODUCT_ID, and DEVICE TYPE in its list of entries.
417480
if valid_vendor_id and valid_product_id and valid_device_type:
418-
logging.info('Found a valid commissioner in the Linux tv-casting-app logs:')
481+
logging.info('Found a valid commissioner in the Linux tv-casting-app output:')
419482
logging.info(valid_discovered_commissioner)
420483
logging.info(valid_vendor_id)
421484
logging.info(valid_product_id)
@@ -454,7 +517,24 @@ def test_launchUrl_fn(tv_casting_app_info: Tuple[subprocess.Popen, TextIO], tv_a
454517
if not parse_tv_casting_app_output_for_launchUrl_msg_success(tv_casting_app_info, log_paths):
455518
handle_casting_failure('Testing launchUrl', log_paths)
456519

457-
logging.info('Testing launchUrl success!\n')
520+
logging.info('Testing launchUrl success!')
521+
522+
523+
def test_subscription_fn(tv_casting_app_info: Tuple[subprocess.Popen, TextIO], log_paths: List[str]):
524+
"""Test the subscription state of the Linux tv-casting-app by validating the `ReportDataMessage` block."""
525+
526+
valid_report_data_msg = parse_tv_casting_app_for_report_data_msg(tv_casting_app_info, log_paths)
527+
528+
if valid_report_data_msg:
529+
logging.info('Found the `ReportDataMessage` block in the Linux tv-casting-app output:')
530+
531+
for line in valid_report_data_msg:
532+
logging.info(line)
533+
534+
logging.info('Testing subscription success!\n')
535+
valid_report_data_msg.clear()
536+
else:
537+
handle_casting_failure('Testing subscription', log_paths)
458538

459539

460540
@click.command()
@@ -504,7 +584,7 @@ def test_casting_fn(tv_app_rel_path, tv_casting_app_rel_path):
504584
valid_discovered_commissioner_number = valid_discovered_commissioner.split('#')[-1].replace('\x1b[0m', '')
505585

506586
test_commissioning_fn(valid_discovered_commissioner_number, tv_casting_app_info, tv_app_info, log_paths)
507-
587+
test_subscription_fn(tv_casting_app_info, log_paths)
508588
test_launchUrl_fn(tv_casting_app_info, tv_app_info, log_paths)
509589

510590

0 commit comments

Comments
 (0)