36
36
# 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.
37
37
TEST_LAUNCHURL_MAX_WAIT_SEC = 10
38
38
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
+
39
42
# File names of logs for the Linux tv-casting-app and the Linux tv-app.
40
43
LINUX_TV_APP_LOGS = 'Linux-tv-app-logs.txt'
41
44
LINUX_TV_CASTING_APP_LOGS = 'Linux-tv-casting-app-logs.txt'
46
49
PRODUCT_ID = 0x8001 # Test product id
47
50
DEVICE_TYPE_CASTING_VIDEO_PLAYER = 0x23 # Device type library 10.3: Casting Video Player
48
51
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
+
49
56
50
57
class ProcessManager :
51
58
"""A context manager for managing subprocesses.
@@ -96,13 +103,19 @@ def extract_value_from_string(line: str) -> str:
96
103
97
104
The string is expected to be in the following format as it is received
98
105
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:
99
109
\x1b [0;34m[1713741926895] [7276:9521344] [DIS] Vendor ID: 65521\x1b [0m
100
110
The integer value to be extracted here is 65521.
101
111
Or:
102
112
\x1b [0;34m[1714583616179] [7029:2386956] [SVR] device Name: Test TV casting app\x1b [0m
103
113
The substring to be extracted here is 'Test TV casting app'.
104
114
"""
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' , '' )
106
119
107
120
return value
108
121
@@ -211,7 +224,8 @@ def validate_identification_declaration_message_on_tv_app(tv_app_info: Tuple[sub
211
224
while True :
212
225
# Check if we exceeded the maximum wait time for validating the device information from the Linux tv-app to the corresponding values from the Linux tv-app.
213
226
if time .time () - start_wait_time > COMMISSIONING_STAGE_MAX_WAIT_SEC :
214
- logging .erro ('The device information from the Linux tv-app output was not validated against the corresponding values from the Linux tv-casting-app output within the timeout.' )
227
+ logging .error (
228
+ 'The device information from the Linux tv-app output was not validated against the corresponding values from the Linux tv-casting-app output within the timeout.' )
215
229
return False
216
230
217
231
tv_app_line = tv_app_process .stdout .readline ()
@@ -221,7 +235,7 @@ def validate_identification_declaration_message_on_tv_app(tv_app_info: Tuple[sub
221
235
linux_tv_app_log_file .flush ()
222
236
223
237
if 'Identification Declaration Start' in tv_app_line :
224
- logging .info ('" Identification Declaration" block from the Linux tv-app output:' )
238
+ logging .info ('Found the ` Identification Declaration` block in the Linux tv-app output:' )
225
239
logging .info (tv_app_line .rstrip ('\n ' ))
226
240
parsing_identification_block = True
227
241
elif parsing_identification_block :
@@ -310,6 +324,56 @@ def validate_commissioning_success(tv_casting_app_info: Tuple[subprocess.Popen,
310
324
return True
311
325
312
326
327
+ def parse_tv_casting_app_for_report_data_msg (tv_casting_app_info : Tuple [subprocess .Popen , TextIO ], log_paths : List [str ]):
328
+ """Parse the Linux tv-casting-app for `ReportDataMessage` block and return the first message block with valid `Cluster` and `Attribute` values."""
329
+ tv_casting_app_process , linux_tv_casting_app_log_file = tv_casting_app_info
330
+
331
+ continue_parsing = False
332
+ report_data_message = []
333
+
334
+ start_wait_time = time .time ()
335
+
336
+ while True :
337
+ # Check if we exceeded the maximum wait time to parse the Linux tv-casting-app output for `ReportDataMessage` block.
338
+ if time .time () - start_wait_time > VERIFY_SUBSCRIPTION_STATE_MAX_WAIT_SEC :
339
+ logging .error (
340
+ 'The relevant `ReportDataMessage` block was not found in the Linux tv-casting-app process within the timeout.' )
341
+ report_data_message .clear ()
342
+ return report_data_message
343
+
344
+ tv_casting_line = tv_casting_app_process .stdout .readline ()
345
+
346
+ if tv_casting_line :
347
+ linux_tv_casting_app_log_file .write (tv_casting_line )
348
+ linux_tv_casting_app_log_file .flush ()
349
+
350
+ if 'ReportDataMessage =' in tv_casting_line :
351
+ report_data_message .append (tv_casting_line .rstrip ('\n ' ))
352
+ continue_parsing = True
353
+ elif continue_parsing :
354
+ report_data_message .append (tv_casting_line .rstrip ('\n ' ))
355
+
356
+ if 'Cluster =' in tv_casting_line :
357
+ cluster_value = extract_value_from_string (tv_casting_line )
358
+ if cluster_value != CLUSTER_MEDIA_PLAYBACK :
359
+ report_data_message .clear ()
360
+ continue_parsing = False
361
+
362
+ elif 'Attribute =' in tv_casting_line :
363
+ attribute_value = extract_value_from_string (tv_casting_line )
364
+ if attribute_value != ATTRIBUTE_CURRENT_PLAYBACK_STATE :
365
+ report_data_message .clear ()
366
+ continue_parsing = False
367
+
368
+ elif 'InteractionModelRevision' in tv_casting_line :
369
+ # Capture the closing brace `}` of the `ReportDataMessage` block.
370
+ tv_casting_line = tv_casting_app_process .stdout .readline ()
371
+ linux_tv_casting_app_log_file .write (tv_casting_line )
372
+ linux_tv_casting_app_log_file .flush ()
373
+ report_data_message .append (tv_casting_line .rstrip ('\n ' ))
374
+ return report_data_message
375
+
376
+
313
377
def parse_tv_app_output_for_launchUrl_msg_success (tv_app_info : Tuple [subprocess .Popen , TextIO ], log_paths : List [str ]):
314
378
"""Parse the Linux tv-app output for the relevant string indicating that the launchUrl was received."""
315
379
@@ -359,7 +423,7 @@ def parse_tv_casting_app_output_for_launchUrl_msg_success(tv_casting_app_info: T
359
423
linux_tv_casting_app_log_file .flush ()
360
424
361
425
if 'InvokeResponseMessage =' in tv_casting_line :
362
- logging .info ('Found the InvokeResponseMessage block in the Linux tv-casting-app output:' )
426
+ logging .info ('Found the ` InvokeResponseMessage` block in the Linux tv-casting-app output:' )
363
427
logging .info (tv_casting_line .rstrip ('\n ' ))
364
428
continue_parsing_invoke_response_msg_block = True
365
429
@@ -415,7 +479,7 @@ def test_discovery_fn(tv_casting_app_info: Tuple[subprocess.Popen, TextIO], log_
415
479
416
480
# A valid commissioner has VENDOR_ID, PRODUCT_ID, and DEVICE TYPE in its list of entries.
417
481
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 :' )
482
+ logging .info ('Found a valid commissioner in the Linux tv-casting-app output :' )
419
483
logging .info (valid_discovered_commissioner )
420
484
logging .info (valid_vendor_id )
421
485
logging .info (valid_product_id )
@@ -445,6 +509,23 @@ def test_commissioning_fn(valid_discovered_commissioner_number, tv_casting_app_i
445
509
handle_casting_failure ('Commissioning' , log_paths )
446
510
447
511
512
+ def test_subscription_fn (tv_casting_app_info : Tuple [subprocess .Popen , TextIO ], log_paths : List [str ]):
513
+ """Test the subscription state of the Linux tv-casting-app by validating the `ReportDataMessage` block."""
514
+
515
+ valid_report_data_msg = parse_tv_casting_app_for_report_data_msg (tv_casting_app_info , log_paths )
516
+
517
+ if valid_report_data_msg :
518
+ logging .info ('Found the `ReportDataMessage` block in the Linux tv-casting-app output:' )
519
+
520
+ for line in valid_report_data_msg :
521
+ logging .info (line )
522
+
523
+ logging .info ('Testing subscription success!\n ' )
524
+ valid_report_data_msg .clear ()
525
+ else :
526
+ handle_casting_failure ('Testing subscription' , log_paths )
527
+
528
+
448
529
def test_launchUrl_fn (tv_casting_app_info : Tuple [subprocess .Popen , TextIO ], tv_app_info : Tuple [subprocess .Popen , TextIO ], log_paths : List [str ]):
449
530
"""Test that the Linux tv-casting-app sent the launchUrl and that the Linux tv-app received the launchUrl."""
450
531
@@ -454,7 +535,7 @@ def test_launchUrl_fn(tv_casting_app_info: Tuple[subprocess.Popen, TextIO], tv_a
454
535
if not parse_tv_casting_app_output_for_launchUrl_msg_success (tv_casting_app_info , log_paths ):
455
536
handle_casting_failure ('Testing launchUrl' , log_paths )
456
537
457
- logging .info ('Testing launchUrl success!\n ' )
538
+ logging .info ('Testing launchUrl success!' )
458
539
459
540
460
541
@click .command ()
@@ -504,7 +585,7 @@ def test_casting_fn(tv_app_rel_path, tv_casting_app_rel_path):
504
585
valid_discovered_commissioner_number = valid_discovered_commissioner .split ('#' )[- 1 ].replace ('\x1b [0m' , '' )
505
586
506
587
test_commissioning_fn (valid_discovered_commissioner_number , tv_casting_app_info , tv_app_info , log_paths )
507
-
588
+ test_subscription_fn ( tv_casting_app_info , log_paths )
508
589
test_launchUrl_fn (tv_casting_app_info , tv_app_info , log_paths )
509
590
510
591
0 commit comments