Skip to content

Commit 8ebfb19

Browse files
Addressed PR comments from @sharadb-amazon.
1 parent 2de194a commit 8ebfb19

File tree

2 files changed

+235
-253
lines changed

2 files changed

+235
-253
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
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 logging
18+
import sys
19+
from enum import Enum
20+
from typing import List, Optional
21+
22+
"""
23+
Define the test sequences with the relevant steps that will be used in the `scripts/tests/run_tv_casting_test.py` for
24+
validating the casting experience between the Linux tv-casting-app and the Linux tv-app.
25+
"""
26+
27+
# The maximum amount of time to wait for the Linux tv-app to start before timeout.
28+
TV_APP_MAX_START_WAIT_SEC = 2
29+
30+
# The maximum default time to wait while parsing for output string(s).
31+
DEFAULT_TIMEOUT_SEC = 10
32+
33+
# Values that identify the Linux tv-app and are noted in the 'Device Configuration' in the Linux tv-app output
34+
# as well as under the 'Discovered Commissioner' details in the Linux tv-casting-app output.
35+
VENDOR_ID = 0xFFF1 # Spec 7.20.2.1 MEI code: test vendor IDs are 0xFFF1 to 0xFFF4
36+
PRODUCT_ID = 0x8001 # Test product id
37+
DEVICE_TYPE_CASTING_VIDEO_PLAYER = 0x23 # Device type library 10.3: Casting Video Player
38+
39+
TEST_TV_CASTING_APP_DEVICE_NAME = 'Test TV casting app' # Test device name for identifying the tv-casting-app
40+
41+
# Values to verify the subscription state against from the `ReportDataMessage` in the Linux tv-casting-app output.
42+
CLUSTER_MEDIA_PLAYBACK = '0x506' # Application Cluster Spec 6.10.3 Cluster ID: Media Playback
43+
ATTRIBUTE_CURRENT_PLAYBACK_STATE = '0x0000_0000' # Application Cluster Spec 6.10.6 Attribute ID: Current State of Playback
44+
45+
46+
class App(Enum):
47+
"""An enumeration of the supported applications."""
48+
49+
TV_APP = 'tv-app'
50+
TV_CASTING_APP = 'tv-casting-app'
51+
52+
53+
class Step:
54+
"""A class to represent a step in a test sequence for validation.
55+
56+
A Step object contains attributes relevant to a test step where each object contains:
57+
- `app` subprocess to parse for `output_msg` or `send input_cmd`
58+
- `timeout_sec` specified the timeout duration for parsing the `output_msg` (optional, defaults to DEFAULT_TIMEOUT_SEC)
59+
- `output_msg` or `input_cmd` (mutually exclusive)
60+
61+
Note: The first entry in the test sequence list of steps should always be the output string to verify that the tv-app
62+
is up and running.
63+
64+
For output message blocks, define the start line, relevant lines, and the last line. If the last line contains trivial closing
65+
characters (e.g., closing brackets, braces, or commas), include the line before it with actual content. For example:
66+
`Step(subprocess_='tv-casting-app', output_msg=['InvokeResponseMessage =', 'exampleData', 'InteractionModelRevision =', '},'])`
67+
68+
For input commands, define the command string with placeholders for variables that need to be updated. For example:
69+
`Step(subprocess_='tv-casting-app', input_cmd='cast request 0\n')`
70+
"""
71+
72+
def __init__(
73+
self,
74+
app: App,
75+
timeout_sec: Optional[int] = DEFAULT_TIMEOUT_SEC,
76+
output_msg: Optional[List[str]] = None,
77+
input_cmd: Optional[str] = None,
78+
):
79+
# Validate that either `output_msg` or `input_cmd` is provided, but not both.
80+
if output_msg is not None and input_cmd is not None:
81+
logging.error('Step cannot contain both `output_msg` and `input_cmd`. Either `output_msg` or `input_cmd` should be provided.')
82+
sys.exit(1)
83+
elif output_msg is None and input_cmd is None:
84+
logging.error('Step must contain either `output_msg` or `input_cmd`. Both are `None`.')
85+
sys.exit(1)
86+
87+
# Define either `App.TV_APP` or `App.TV_CASTING_APP` on which we need to parse for `output_msg` or send `input_cmd`.
88+
self.app = app
89+
90+
# Define the maximum time in seconds for timeout while parsing for the `output_msg`. If not provided, then we use the DEFAULT_TIMEOUT_SEC.
91+
self.timeout_sec = timeout_sec
92+
93+
# Define the `output_msg` that we need to parse for in a list format.
94+
self.output_msg = output_msg
95+
96+
# Define the `input_cmd` that we need to send to either the `App.TV_APP` or `App.TV_CASTING_APP`.
97+
self.input_cmd = input_cmd
98+
99+
100+
class Sequence:
101+
"""A class representing a sequence of steps for testing the casting experience between the Linux tv-casting-app and the tv-app.
102+
103+
A Sequence object needs to be defined with an appropriate test sequence `name` along with its list of `Step` objects that will
104+
be used for validating the casting experience.
105+
"""
106+
107+
def __init__(self, name: str, steps: List[Step]):
108+
self.name = name
109+
self.steps = steps
110+
111+
112+
def get_test_sequence_by_name(test_sequences: List[Sequence], test_sequence_name: str) -> Optional[Sequence]:
113+
"""Retrieve a test sequence from a list of sequences by its name."""
114+
115+
for sequence in test_sequences:
116+
if sequence.name == test_sequence_name:
117+
return sequence
118+
return None
119+
120+
121+
def get_test_sequences() -> List[Sequence]:
122+
"""Retrieve all the test sequences to validate the casting experience between the Linux tv-casting-app and the Linux tv-app."""
123+
124+
test_sequences = [
125+
Sequence(
126+
name='commissionee_generated_passcode_test',
127+
steps=[
128+
# Validate that the tv-app is up and running.
129+
Step(app=App.TV_APP, timeout_sec=TV_APP_MAX_START_WAIT_SEC, output_msg=['Started commissioner']),
130+
131+
# 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.
132+
Step(app=App.TV_CASTING_APP, output_msg=['Discovered Commissioner #0', f'Vendor ID: {VENDOR_ID}', f'Product ID: {PRODUCT_ID}',
133+
f'Device Type: {DEVICE_TYPE_CASTING_VIDEO_PLAYER}', 'Supports Commissioner Generated Passcode: true']),
134+
135+
# Validate that we are ready to send `cast request` command to the tv-casting-app subprocess.
136+
Step(app=App.TV_CASTING_APP, output_msg=['Example: cast request 0']),
137+
138+
# Send `cast request {valid_discovered_commissioner_number}\n` command to the tv-casting-app subprocess.
139+
Step(app=App.TV_CASTING_APP, input_cmd='cast request 0\n'),
140+
141+
# 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`.
142+
Step(app=App.TV_CASTING_APP, output_msg=['Identification Declaration Start', f'device Name: {TEST_TV_CASTING_APP_DEVICE_NAME}',
143+
f'vendor id: {VENDOR_ID}', f'product id: {PRODUCT_ID}', 'Identification Declaration End']),
144+
145+
# Validate that the `Identification Declaration` message block in the tv-app output has the expected values for `device Name`, `vendor id`, and `product id`.
146+
Step(app=App.TV_APP, output_msg=['Identification Declaration Start', f'device Name: {TEST_TV_CASTING_APP_DEVICE_NAME}',
147+
f'vendor id: {VENDOR_ID}', f'product id: {PRODUCT_ID}', 'Identification Declaration End']),
148+
149+
# Validate that we received the cast request from the tv-casting-app on the tv-app output.
150+
Step(app=App.TV_APP,
151+
output_msg=['PROMPT USER: Test TV casting app is requesting permission to cast to this TV, approve?']),
152+
153+
# Validate that we received the instructions on the tv-app output for sending the `controller ux ok` command.
154+
Step(app=App.TV_APP, output_msg=['Via Shell Enter: controller ux ok|cancel']),
155+
156+
# Send `controller ux ok` command to the tv-app subprocess.
157+
Step(app=App.TV_APP, input_cmd='controller ux ok\n'),
158+
159+
# Validate that pairing succeeded between the tv-casting-app and the tv-app.
160+
Step(app=App.TV_APP, output_msg=['Secure Pairing Success']),
161+
162+
# Validate that commissioning succeeded in the tv-casting-app output.
163+
Step(app=App.TV_CASTING_APP, output_msg=['Commissioning completed successfully']),
164+
165+
# Validate that commissioning succeeded in the tv-app output.
166+
Step(app=App.TV_APP, output_msg=['------PROMPT USER: commissioning success']),
167+
168+
# Validate the subscription state by looking at the `Cluster` and `Attribute` values in the `ReportDataMessage` block in the tv-casting-app output.
169+
Step(app=App.TV_CASTING_APP, output_msg=[
170+
'ReportDataMessage =', f'Cluster = {CLUSTER_MEDIA_PLAYBACK}', f'Attribute = {ATTRIBUTE_CURRENT_PLAYBACK_STATE}', 'InteractionModelRevision =', '}']),
171+
172+
# Validate the LaunchURL in the tv-app output.
173+
Step(app=App.TV_APP,
174+
output_msg=['ContentLauncherManager::HandleLaunchUrl TEST CASE ContentURL=https://www.test.com/videoid DisplayString=Test video']),
175+
176+
# Validate the LaunchURL in the tv-casting-app output.
177+
Step(app=App.TV_CASTING_APP, output_msg=['InvokeResponseMessage =',
178+
'exampleData', 'InteractionModelRevision =', '},'])
179+
]
180+
)
181+
]
182+
183+
return test_sequences

0 commit comments

Comments
 (0)