forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simplify the implementation of
run_tv_casting_test.py
for easier ad…
…dition of future test sequences that verifies that Linux tv-casting-app continues to work with Linux tv-app. (project-chip#33855) * Simplify the implementation of `run_tv_casting_test.py` for easier addition of future test sequences that verifies that Linux tv-casting-app continues to work with Linux tv-app. * Addressed PR comments from @sharadb-amazon. * Addressed @sharadb-amazon PR comments. Also restructured the code to prevent circular import issues. * Run restyle. * Fixed typo.
- Loading branch information
1 parent
6438249
commit c4374a6
Showing
3 changed files
with
462 additions
and
520 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#!/usr/bin/env -S python3 -B | ||
|
||
# Copyright (c) 2024 Project CHIP Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from enum import Enum | ||
from typing import List, Optional | ||
|
||
""" | ||
This file defines the utility classes for creating and managing test sequences to validate the casting experience between | ||
the Linux tv-casting-app and the Linux tv-app. It includes an enumeration for the supported applications (App), a class to | ||
represent individual steps in a test sequence (Step), and a class to represent a complete test sequence (Sequence). | ||
Additionally, it provides helper functions to retrieve specific test sequences or all defined test sequences. | ||
""" | ||
|
||
|
||
class App(Enum): | ||
"""An enumeration of the supported applications.""" | ||
|
||
TV_APP = 'tv-app' | ||
TV_CASTING_APP = 'tv-casting-app' | ||
|
||
|
||
class Step: | ||
"""A class to represent a step in a test sequence for validation. | ||
A `Step` object contains attributes relevant to a test step where each object contains: | ||
- `app` subprocess to parse for `output_msg` or send `input_cmd` | ||
- `timeout_sec` specified the timeout duration for parsing the `output_msg` (optional, defaults to DEFAULT_TIMEOUT_SEC) | ||
- `output_msg` or `input_cmd` (mutually exclusive) | ||
For output message blocks, define the start line, relevant lines, and the last line. If the last line contains trivial closing | ||
characters (e.g., closing brackets, braces, or commas), include the line before it with actual content. For example: | ||
`Step(subprocess_='tv-casting-app', output_msg=['InvokeResponseMessage =', 'exampleData', 'InteractionModelRevision =', '},'])` | ||
For input commands, define the command string with placeholders for variables that need to be updated. For example: | ||
`Step(subprocess_='tv-casting-app', input_cmd='cast request 0\n')` | ||
""" | ||
|
||
# The maximum default time to wait while parsing for output string(s). | ||
DEFAULT_TIMEOUT_SEC = 10 | ||
|
||
def __init__( | ||
self, | ||
app: App, | ||
timeout_sec: Optional[int] = DEFAULT_TIMEOUT_SEC, | ||
output_msg: Optional[List[str]] = None, | ||
input_cmd: Optional[str] = None, | ||
): | ||
# Validate that either `output_msg` or `input_cmd` is provided, but not both. | ||
if output_msg is not None and input_cmd is not None: | ||
raise ValueError( | ||
'Step cannot contain both `output_msg` and `input_cmd`. Either `output_msg` or `input_cmd` should be provided.') | ||
elif output_msg is None and input_cmd is None: | ||
raise ValueError('Step must contain either `output_msg` or `input_cmd`. Both are `None`.') | ||
|
||
# Define either `App.TV_APP` or `App.TV_CASTING_APP` on which we need to parse for `output_msg` or send `input_cmd`. | ||
self.app = app | ||
|
||
# Define the maximum time in seconds for timeout while parsing for the `output_msg`. If not provided, then we use the DEFAULT_TIMEOUT_SEC. | ||
self.timeout_sec = timeout_sec | ||
|
||
# Define the `output_msg` that we need to parse for in a list format. | ||
self.output_msg = output_msg | ||
|
||
# Define the `input_cmd` that we need to send to either the `App.TV_APP` or `App.TV_CASTING_APP`. | ||
self.input_cmd = input_cmd | ||
|
||
|
||
class Sequence: | ||
"""A class representing a sequence of steps for testing the casting experience between the Linux tv-casting-app and the tv-app. | ||
A Sequence object needs to be defined with an appropriate test sequence `name` along with its list of `Step` objects that will | ||
be used for validating the casting experience. | ||
""" | ||
|
||
def __init__(self, name: str, steps: List[Step]): | ||
self.name = name | ||
self.steps = steps | ||
|
||
@staticmethod | ||
def get_test_sequence_by_name(test_sequences: List['Sequence'], test_sequence_name: str) -> Optional['Sequence']: | ||
"""Retrieve a test sequence from a list of sequences by its name.""" | ||
|
||
for sequence in test_sequences: | ||
if sequence.name == test_sequence_name: | ||
return sequence | ||
return None | ||
|
||
@staticmethod | ||
def get_test_sequences() -> List['Sequence']: | ||
"""Retrieve all the test sequences to validate the casting experience between the Linux tv-casting-app and the Linux tv-app.""" | ||
|
||
from linux.tv_casting_test_sequences import test_sequences | ||
|
||
return test_sequences |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
#!/usr/bin/env -S python3 -B | ||
|
||
# Copyright (c) 2024 Project CHIP Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from linux.tv_casting_test_sequence_utils import App, Sequence, Step | ||
|
||
""" | ||
In this file, we define the test sequences with the relevant steps that will be used in the `scripts/tests/run_tv_casting_test.py` | ||
for validating the casting experience between the Linux tv-casting-app and the Linux tv-app. | ||
At the beginning of each test sequence we need to indicate the start up of the tv-app using the `START_APP` string as the `input_cmd` | ||
followed by the same for the tv-casting-app. On the other hand, at the end of each test sequence we need to ensure that each app will | ||
be stopped by providing the `STOP_APP` string as the `input_cmd`. As noted in the example below of `example_test_sequence`, the first | ||
four steps pertain to starting the apps while the last two are for signaling stopping the apps. | ||
Note: `START_APP` and `STOP_APP` are reserved for signaling the starting and stopping of apps. | ||
Example: | ||
test_sequences = [ | ||
Sequence( | ||
name='example_test_sequence', | ||
step=[ | ||
# Signal to start the tv-app. | ||
Step(app=App.TV_APP, input_cmd=START_APP), | ||
# Validate that the tv-app is up and running. | ||
Step(app=App.TV_APP, timeout_sec=APP_MAX_START_WAIT_SEC, output_msg=['Started commissioner']), | ||
# Signal to start the tv-casting-app. | ||
Step(app=App.TV_CASTING_APP, input_cmd=START_APP), | ||
# Validate that the server is properly initialized in the tv-casting-app output. | ||
Step(app=App.TV_CASTING_APP, timeout_sec=APP_MAX_START_WAIT_SEC, output_msg=['Server initialization complete']), | ||
# Additional steps for testing the casting experience. | ||
# Signal to stop the tv-casting-app as we finished validation. | ||
Step(app=App.TV_CASTING_APP, input_cmd=STOP_APP), | ||
# Signal to stop the tv-app as we finished validation. | ||
Step(app=App.TV_APP, input_cmd=STOP_APP) | ||
] | ||
) | ||
] | ||
""" | ||
|
||
# Signal to start the app. | ||
START_APP = 'START' | ||
|
||
# Signal to stop the app. | ||
STOP_APP = 'STOP' | ||
|
||
# The maximum amount of time to wait for the Linux tv-app or Linux tv-casting-app to start before timeout. | ||
APP_MAX_START_WAIT_SEC = 2 | ||
|
||
# Values that identify the Linux tv-app and are noted in the 'Device Configuration' in the Linux tv-app output | ||
# as well as under the 'Discovered Commissioner' details in the Linux tv-casting-app output. | ||
VENDOR_ID = 0xFFF1 # Spec 7.20.2.1 MEI code: test vendor IDs are 0xFFF1 to 0xFFF4 | ||
PRODUCT_ID = 0x8001 # Test product id | ||
DEVICE_TYPE_CASTING_VIDEO_PLAYER = 0x23 # Device type library 10.3: Casting Video Player | ||
|
||
TEST_TV_CASTING_APP_DEVICE_NAME = 'Test TV casting app' # Test device name for identifying the tv-casting-app | ||
|
||
# Values to verify the subscription state against from the `ReportDataMessage` in the Linux tv-casting-app output. | ||
CLUSTER_MEDIA_PLAYBACK = '0x506' # Application Cluster Spec 6.10.3 Cluster ID: Media Playback | ||
ATTRIBUTE_CURRENT_PLAYBACK_STATE = '0x0000_0000' # Application Cluster Spec 6.10.6 Attribute ID: Current State of Playback | ||
|
||
test_sequences = [ | ||
Sequence( | ||
name='commissionee_generated_passcode_test', | ||
steps=[ | ||
# Signal to start the tv-app. | ||
Step(app=App.TV_APP, input_cmd=START_APP), | ||
|
||
# Validate that the tv-app is up and running. | ||
Step(app=App.TV_APP, timeout_sec=APP_MAX_START_WAIT_SEC, output_msg=['Started commissioner']), | ||
|
||
# Signal to start the tv-casting-app. | ||
Step(app=App.TV_CASTING_APP, input_cmd=START_APP), | ||
|
||
# Validate that the server is properly initialized in the tv-casting-app output. | ||
Step(app=App.TV_CASTING_APP, timeout_sec=APP_MAX_START_WAIT_SEC, output_msg=['Server initialization complete']), | ||
|
||
# Validate that there is a valid discovered commissioner with {VENDOR_ID}, {PRODUCT_ID}, and {DEVICE_TYPE_CASTING_VIDEO_PLAYER} in the tv-casting-app output. | ||
Step(app=App.TV_CASTING_APP, output_msg=['Discovered Commissioner #0', f'Vendor ID: {VENDOR_ID}', f'Product ID: {PRODUCT_ID}', | ||
f'Device Type: {DEVICE_TYPE_CASTING_VIDEO_PLAYER}', 'Supports Commissioner Generated Passcode: true']), | ||
|
||
# Validate that we are ready to send `cast request` command to the tv-casting-app subprocess. | ||
Step(app=App.TV_CASTING_APP, output_msg=['Example: cast request 0']), | ||
|
||
# Send `cast request {valid_discovered_commissioner_number}\n` command to the tv-casting-app subprocess. | ||
Step(app=App.TV_CASTING_APP, input_cmd='cast request 0\n'), | ||
|
||
# Validate that the `Identification Declaration` message block in the tv-casting-app output has the expected values for `device Name`, `vendor id`, and `product id`. | ||
Step(app=App.TV_CASTING_APP, output_msg=['Identification Declaration Start', f'device Name: {TEST_TV_CASTING_APP_DEVICE_NAME}', | ||
f'vendor id: {VENDOR_ID}', f'product id: {PRODUCT_ID}', 'Identification Declaration End']), | ||
|
||
# Validate that the `Identification Declaration` message block in the tv-app output has the expected values for `device Name`, `vendor id`, and `product id`. | ||
Step(app=App.TV_APP, output_msg=['Identification Declaration Start', f'device Name: {TEST_TV_CASTING_APP_DEVICE_NAME}', | ||
f'vendor id: {VENDOR_ID}', f'product id: {PRODUCT_ID}', 'Identification Declaration End']), | ||
|
||
# Validate that we received the cast request from the tv-casting-app on the tv-app output. | ||
Step(app=App.TV_APP, | ||
output_msg=['PROMPT USER: Test TV casting app is requesting permission to cast to this TV, approve?']), | ||
|
||
# Validate that we received the instructions on the tv-app output for sending the `controller ux ok` command. | ||
Step(app=App.TV_APP, output_msg=['Via Shell Enter: controller ux ok|cancel']), | ||
|
||
# Send `controller ux ok` command to the tv-app subprocess. | ||
Step(app=App.TV_APP, input_cmd='controller ux ok\n'), | ||
|
||
# Validate that pairing succeeded between the tv-casting-app and the tv-app. | ||
Step(app=App.TV_APP, output_msg=['Secure Pairing Success']), | ||
|
||
# Validate that commissioning succeeded in the tv-casting-app output. | ||
Step(app=App.TV_CASTING_APP, output_msg=['Commissioning completed successfully']), | ||
|
||
# Validate that commissioning succeeded in the tv-app output. | ||
Step(app=App.TV_APP, output_msg=['------PROMPT USER: commissioning success']), | ||
|
||
# Validate the subscription state by looking at the `Cluster` and `Attribute` values in the `ReportDataMessage` block in the tv-casting-app output. | ||
Step(app=App.TV_CASTING_APP, output_msg=[ | ||
'ReportDataMessage =', f'Cluster = {CLUSTER_MEDIA_PLAYBACK}', f'Attribute = {ATTRIBUTE_CURRENT_PLAYBACK_STATE}', 'InteractionModelRevision =', '}']), | ||
|
||
# Validate the LaunchURL in the tv-app output. | ||
Step(app=App.TV_APP, | ||
output_msg=['ContentLauncherManager::HandleLaunchUrl TEST CASE ContentURL=https://www.test.com/videoid DisplayString=Test video']), | ||
|
||
# Validate the LaunchURL in the tv-casting-app output. | ||
Step(app=App.TV_CASTING_APP, output_msg=['InvokeResponseMessage =', | ||
'exampleData', 'InteractionModelRevision =', '},']), | ||
|
||
# Signal to stop the tv-casting-app as we finished validation. | ||
Step(app=App.TV_CASTING_APP, input_cmd=STOP_APP), | ||
|
||
# Signal to stop the tv-app as we finished validation. | ||
Step(app=App.TV_APP, input_cmd=STOP_APP) | ||
] | ||
) | ||
] |
Oops, something went wrong.