Skip to content

Commit 619988e

Browse files
authored
[CherryPick] Add CameraAVSM test scripts for test cases in CameraAVSM Testplan PR 5640 (#42832) (#42857)
* Add CameraAVSM test scripts for test cases in CameraAVSM Testplan PR 5640 (#42832) * Add CameraAVSM test scripts for test cases in testplan PR CHIP-Specifications/chip-test-plans#5640 * Fixes for copilot review comments * Add the app-ready-pattern for the app to signal when it is back after (#42883) restarting so that the test script can connect back.
1 parent 4564cd2 commit 619988e

File tree

4 files changed

+709
-0
lines changed

4 files changed

+709
-0
lines changed

src/python_testing/TC_AVSM_2_18.py

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#
2+
# Copyright (c) 2025 Project CHIP Authors
3+
# All rights reserved.
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+
# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments
18+
# for details about the block below.
19+
#
20+
# === BEGIN CI TEST ARGUMENTS ===
21+
# test-runner-runs:
22+
# run1:
23+
# app: ${CAMERA_APP}
24+
# app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json
25+
# app-ready-pattern: "APP STATUS: Starting event loop"
26+
# script-args: >
27+
# --storage-path admin_storage.json
28+
# --commissioning-method on-network
29+
# --discriminator 1234
30+
# --passcode 20202021
31+
# --PICS src/app/tests/suites/certification/ci-pics-values
32+
# --trace-to json:${TRACE_TEST_JSON}.json
33+
# --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto
34+
# --endpoint 1
35+
# factory-reset: true
36+
# quiet: true
37+
# === END CI TEST ARGUMENTS ===
38+
39+
import logging
40+
41+
from mobly import asserts
42+
from TC_AVSMTestBase import AVSMTestBase
43+
44+
import matter.clusters as Clusters
45+
from matter.testing.decorators import has_feature, run_if_endpoint_matches
46+
from matter.testing.matter_testing import MatterBaseTest
47+
from matter.testing.runner import TestStep, default_matter_test_main
48+
49+
log = logging.getLogger(__name__)
50+
51+
52+
class TC_AVSM_2_18(MatterBaseTest, AVSMTestBase):
53+
54+
def desc_TC_AVSM_2_18(self) -> str:
55+
return "[TC-AVSM-2.18] Validate persistence of allocated video streams with DUT"
56+
57+
def steps_TC_AVSM_2_18(self) -> list[TestStep]:
58+
return [
59+
TestStep(1, "Commissioning, already done", is_commissioning=True),
60+
TestStep(2, "TH reads FeatureMap attribute from CameraAVStreamManagement Cluster on DUT. Verify F_VDO is supported."),
61+
TestStep(3, "TH reads AllocatedVideoStreams attribute from CameraAVStreamManagement Cluster on DUT. Verify the number of allocated video streams in the list is 0."),
62+
TestStep(4, "TH reads StreamUsagePriorities attribute from CameraAVStreamManagement Cluster on DUT. Store this value in aStreamUsagePriorities."),
63+
TestStep(5, "TH reads RateDistortionTradeOffPoints attribute from CameraAVStreamManagement Cluster on DUT. Store this value in aRateDistortionTradeOffPoints."),
64+
TestStep(6, "TH reads MinViewportResolution attribute from CameraAVStreamManagement Cluster on DUT. Store this value in aMinViewportResolution."),
65+
TestStep(7, "TH reads VideoSensorParams attribute from CameraAVStreamManagement Cluster on DUT. Store this value in aVideoSensorParams."),
66+
TestStep(8, "TH reads MaxEncodedPixelrate attribute from CameraAVStreamManagement Cluster on DUT. Store this value in aMaxEncodedPixelRate."),
67+
TestStep(9, "If F_WMARK is supported, TH sets it's local aWatermark to True, otherwise this is Null."),
68+
TestStep(10, "If F_OSD is supported, TH sets its local aOSD to True, otherwise this is Null."),
69+
TestStep(11, "TH sets StreamUsage from aStreamUsagePriorities. TH sets VideoCodec, MinResolution, MaxResolution, MinBitRate, MaxBitRate conforming with aRateDistortionTradeOffPoints. TH sets MinFrameRate, MaxFrameRate conforming with aVideoSensorParams. TH sets the KeyFrameInterval = 4000. TH sets WatermarkEnabled to aWatermark, TH also sets OSDEnabled to aOSD. TH sends the VideoStreamAllocate command with these arguments."),
70+
TestStep(12, "TH reads AllocatedVideoStreams attribute from CameraAVStreamManagement Cluster on DUT. Verify the number of allocated video streams in the list is 1."),
71+
TestStep(13, "TH reboots the DUT."),
72+
TestStep(14, "TH waits for the DUT to come back online."),
73+
TestStep(15, "TH reads AllocatedVideoStreams attribute from CameraAVStreamManagement Cluster on DUT. Verify the number of allocated video streams in the list is 1 and the stream info is identical to what was provided in step 11."),
74+
TestStep(16, "TH sends the VideoStreamDeallocate command with VideoStreamID set to myStreamID."),
75+
TestStep(17, "TH reads AllocatedVideoStreams attribute from CameraAVStreamManagement Cluster on DUT. Verify the number of allocated video streams in the list is 0."),
76+
TestStep(18, "TH reboots the DUT."),
77+
TestStep(19, "TH waits for the DUT to come back online."),
78+
TestStep(20, "TH reads AllocatedVideoStreams attribute from CameraAVStreamManagement Cluster on DUT. Verify the number of allocated video streams in the list is 0."),
79+
]
80+
81+
def pics_TC_AVSM_2_18(self) -> list[str]:
82+
return ["AVSM.S", "AVSM.S.F_VDO"]
83+
84+
@run_if_endpoint_matches(
85+
has_feature(Clusters.CameraAvStreamManagement, Clusters.CameraAvStreamManagement.Bitmaps.Feature.kVideo)
86+
)
87+
async def test_TC_AVSM_2_18(self):
88+
endpoint = self.get_endpoint()
89+
cluster = Clusters.CameraAvStreamManagement
90+
attr = Clusters.CameraAvStreamManagement.Attributes
91+
commands = Clusters.CameraAvStreamManagement.Commands
92+
93+
self.step(1)
94+
95+
self.step(2)
96+
feature_map = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.FeatureMap)
97+
has_f_vdo = (feature_map & cluster.Bitmaps.Feature.kVideo) != 0
98+
asserts.assert_true(has_f_vdo, "FeatureMap F_VDO is not set")
99+
100+
self.step(3)
101+
allocated_video_streams = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.AllocatedVideoStreams)
102+
asserts.assert_equal(len(allocated_video_streams), 0, "AllocatedVideoStreams should be empty")
103+
104+
self.step(4)
105+
stream_usage_priorities = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.StreamUsagePriorities)
106+
asserts.assert_greater(len(stream_usage_priorities), 0, "StreamUsagePriorities should not be empty")
107+
108+
self.step(5)
109+
rate_distortion_trade_off_points = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.RateDistortionTradeOffPoints)
110+
asserts.assert_greater(len(rate_distortion_trade_off_points), 0, "RateDistortionTradeOffPoints should not be empty")
111+
112+
self.step(6)
113+
min_viewport_resolution = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.MinViewportResolution)
114+
log.info(f"Rx'd MinViewportResolution: {min_viewport_resolution}")
115+
116+
self.step(7)
117+
video_sensor_params = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.VideoSensorParams)
118+
log.info(f"Rx'd VideoSensorParams: {video_sensor_params}")
119+
120+
self.step(8)
121+
max_encoded_pixel_rate = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.MaxEncodedPixelRate)
122+
log.info(f"Rx'd MaxEncodedPixelRate: {max_encoded_pixel_rate}")
123+
124+
self.step(9)
125+
has_f_wmark = (feature_map & cluster.Bitmaps.Feature.kWatermark) != 0
126+
watermark_enabled = True if has_f_wmark else None
127+
128+
self.step(10)
129+
has_f_osd = (feature_map & cluster.Bitmaps.Feature.kOnScreenDisplay) != 0
130+
osd_enabled = True if has_f_osd else None
131+
132+
self.step(11)
133+
# Select valid parameters based on device capabilities
134+
stream_usage = stream_usage_priorities[0]
135+
trade_off_point = rate_distortion_trade_off_points[0]
136+
video_codec = trade_off_point.codec
137+
min_resolution = min_viewport_resolution
138+
min_bit_rate = trade_off_point.minBitRate
139+
max_bit_rate = trade_off_point.minBitRate
140+
min_frame_rate = 30
141+
max_frame_rate = video_sensor_params.maxFPS
142+
key_frame_interval = 4000
143+
144+
cmd = commands.VideoStreamAllocate(
145+
streamUsage=stream_usage,
146+
videoCodec=video_codec,
147+
minFrameRate=min_frame_rate,
148+
maxFrameRate=max_frame_rate,
149+
minResolution=min_resolution,
150+
maxResolution=cluster.Structs.VideoResolutionStruct(
151+
width=video_sensor_params.sensorWidth, height=video_sensor_params.sensorHeight
152+
),
153+
minBitRate=min_bit_rate,
154+
maxBitRate=max_bit_rate,
155+
keyFrameInterval=key_frame_interval,
156+
watermarkEnabled=watermark_enabled,
157+
OSDEnabled=osd_enabled
158+
)
159+
160+
resp = await self.send_single_cmd(endpoint=endpoint, cmd=cmd)
161+
my_stream_id = resp.videoStreamID
162+
asserts.assert_is_not_none(my_stream_id, "VideoStreamID should not be None")
163+
164+
# Store the allocated stream info for comparison after reboot
165+
allocated_stream_info = cluster.Structs.VideoStreamStruct(
166+
videoStreamID=my_stream_id,
167+
streamUsage=stream_usage,
168+
videoCodec=video_codec,
169+
minResolution=min_resolution,
170+
maxResolution=cluster.Structs.VideoResolutionStruct(
171+
width=video_sensor_params.sensorWidth, height=video_sensor_params.sensorHeight
172+
),
173+
minBitRate=min_bit_rate,
174+
maxBitRate=max_bit_rate,
175+
minFrameRate=min_frame_rate,
176+
maxFrameRate=max_frame_rate,
177+
keyFrameInterval=key_frame_interval,
178+
watermarkEnabled=watermark_enabled,
179+
OSDEnabled=osd_enabled,
180+
referenceCount=0
181+
)
182+
183+
self.step(12)
184+
allocated_video_streams = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.AllocatedVideoStreams)
185+
asserts.assert_equal(len(allocated_video_streams), 1, "AllocatedVideoStreams should have 1 entry")
186+
187+
self.step(13)
188+
await self.request_device_reboot()
189+
self.step(14)
190+
# Wait for device to be online is handled by request_device_reboot
191+
192+
self.step(15)
193+
allocated_video_streams = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.AllocatedVideoStreams)
194+
asserts.assert_equal(len(allocated_video_streams), 1, "AllocatedVideoStreams should have 1 entry after reboot")
195+
# Compare the structs, fields should be the same, except referenceCount, which is not persisted
196+
retrieved_stream = allocated_video_streams[0]
197+
asserts.assert_equal(retrieved_stream.videoStreamID, allocated_stream_info.videoStreamID, "videoStreamID mismatch")
198+
asserts.assert_equal(retrieved_stream.streamUsage, allocated_stream_info.streamUsage, "streamUsage mismatch")
199+
asserts.assert_equal(retrieved_stream.videoCodec, allocated_stream_info.videoCodec, "videoCodec mismatch")
200+
asserts.assert_equal(retrieved_stream.minResolution, allocated_stream_info.minResolution, "minResolution mismatch")
201+
asserts.assert_equal(retrieved_stream.maxResolution, allocated_stream_info.maxResolution, "maxResolution mismatch")
202+
asserts.assert_equal(retrieved_stream.minBitRate, allocated_stream_info.minBitRate, "minBitRate mismatch")
203+
asserts.assert_equal(retrieved_stream.maxBitRate, allocated_stream_info.maxBitRate, "maxBitRate mismatch")
204+
asserts.assert_equal(retrieved_stream.minFrameRate, allocated_stream_info.minFrameRate, "minFrameRate mismatch")
205+
asserts.assert_equal(retrieved_stream.maxFrameRate, allocated_stream_info.maxFrameRate, "maxFrameRate mismatch")
206+
asserts.assert_equal(retrieved_stream.keyFrameInterval, allocated_stream_info.keyFrameInterval, "keyFrameInterval mismatch")
207+
asserts.assert_equal(retrieved_stream.watermarkEnabled, allocated_stream_info.watermarkEnabled, "watermarkEnabled mismatch")
208+
asserts.assert_equal(retrieved_stream.OSDEnabled, allocated_stream_info.OSDEnabled, "OSDEnabled mismatch")
209+
210+
self.step(16)
211+
await self.send_single_cmd(cmd=commands.VideoStreamDeallocate(videoStreamID=my_stream_id), endpoint=endpoint)
212+
213+
self.step(17)
214+
allocated_video_streams = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.AllocatedVideoStreams)
215+
asserts.assert_equal(len(allocated_video_streams), 0, "AllocatedVideoStreams should be empty after deallocate")
216+
217+
self.step(18)
218+
await self.request_device_reboot()
219+
self.step(19)
220+
221+
self.step(20)
222+
allocated_video_streams = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attr.AllocatedVideoStreams)
223+
asserts.assert_equal(len(allocated_video_streams), 0, "AllocatedVideoStreams should be empty after reboot")
224+
225+
226+
if __name__ == "__main__":
227+
default_matter_test_main()

0 commit comments

Comments
 (0)