Skip to content

Commit fbbcc7d

Browse files
Fix most TC-SWTCH-2.4 remaining issues (project-chip#34677)
- Move 2.4 in a better place in the file - Add test steps properly - Allow default button press position override Issue project-chip#34656 Testing done: - Test still passes on DUT with automation
1 parent f2f3d0e commit fbbcc7d

File tree

1 file changed

+132
-123
lines changed

1 file changed

+132
-123
lines changed

src/python_testing/TC_SWTCH.py

Lines changed: 132 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,28 @@
4545
logger = logging.getLogger(__name__)
4646

4747

48-
class TC_SwitchTests(MatterBaseTest):
49-
def __init__(self, *args, **kwargs):
50-
super().__init__(*args, **kwargs)
48+
def bump_substep(step: str) -> str:
49+
"""Given a string like "5a", bump it to "5b", or "6c" to "6d" """
50+
if len(step) == 0:
51+
raise ValueError("Can't bump empty steps!")
5152

52-
def desc_TC_SWTCH_2_4(self) -> str:
53-
"""Returns a description of this test"""
54-
return "[TC-SWTCH-2.4] Momentary Switch Long Press Verification"
53+
end_char = step[-1]
54+
if not end_char.isalpha():
55+
return step + "a"
5556

56-
# TODO(#34656): Fill test steps
57-
# def steps_TC_SWTCH_2_4(self) -> list[TestStep]:
58-
# steps = [
59-
# TestStep("0", "Commissioning, already done", is_commissioning=True),
60-
# # TODO: fill when test is done
61-
# ]
57+
step_prefix = step[:-1]
58+
next_end_char = chr(ord(end_char) + 1)
59+
if ord(next_end_char) > ord('z'):
60+
raise ValueError(f"Reached max substep for step '{step}'")
61+
next_step = step_prefix + next_end_char
6262

63-
# return steps
63+
return next_step
64+
65+
66+
class TC_SwitchTests(MatterBaseTest):
67+
def __init__(self, *args, **kwargs):
68+
super().__init__(*args, **kwargs)
69+
self._default_pressed_position = self.user_params.get("default_pressed_position", 1)
6470

6571
def _send_named_pipe_command(self, command_dict: dict[str, Any]):
6672
app_pid = self.matter_test_config.app_pid
@@ -164,14 +170,6 @@ def _ask_for_release(self):
164170
else:
165171
time.sleep(self.keep_pressed_delay/1000)
166172

167-
def _placeholder_for_step(self, step_id: str):
168-
# TODO(#34656): Global search an replace of `self._placeholder_for_step` with `self.step` when done.
169-
logging.info(f"Step {step_id}")
170-
pass
171-
172-
def _placeholder_for_skip(self, step_id: str):
173-
logging.info(f"Skipped step {step_id}")
174-
175173
def _await_sequence_of_reports(self, report_queue: queue.Queue, endpoint_id: int, attribute: TypedAttributePath, sequence: list[Any], timeout_sec: float):
176174
start_time = time.time()
177175
elapsed = 0.0
@@ -269,93 +267,6 @@ def _expect_no_events_for_cluster(self, event_queue: queue.Queue, endpoint_id: i
269267

270268
logging.info(f"Successfully waited for no further events on {expected_cluster} for {elapsed:.1f} seconds")
271269

272-
@per_endpoint_test(has_feature(Clusters.Switch, Clusters.Switch.Bitmaps.Feature.kMomentarySwitch))
273-
async def test_TC_SWTCH_2_4(self):
274-
# TODO(#34656): Make this come from PIXIT
275-
switch_pressed_position = 1
276-
post_prompt_settle_delay_seconds = 10.0
277-
278-
# Commission DUT - already done
279-
280-
# Read feature map to set bool markers
281-
cluster = Clusters.Objects.Switch
282-
feature_map = await self.read_single_attribute_check_success(cluster, attribute=cluster.Attributes.FeatureMap)
283-
284-
has_ms_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitch) != 0
285-
has_msr_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitchRelease) != 0
286-
has_msl_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitchLongPress) != 0
287-
has_as_feature = (feature_map & cluster.Bitmaps.Feature.kActionSwitch) != 0
288-
# has_msm_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitchMultiPress) != 0
289-
290-
if not has_ms_feature:
291-
logging.info("Skipping rest of test: SWTCH.S.F01(MS) feature not present")
292-
self.skip_all_remaining_steps("2")
293-
294-
endpoint_id = self.matter_test_config.endpoint
295-
296-
# Step 1: Set up subscription to all Switch cluster events
297-
self._placeholder_for_step("1")
298-
event_listener = EventChangeCallback(cluster)
299-
attrib_listener = ClusterAttributeChangeAccumulator(cluster)
300-
await event_listener.start(self.default_controller, self.dut_node_id, endpoint=endpoint_id)
301-
await attrib_listener.start(self.default_controller, self.dut_node_id, endpoint=endpoint_id)
302-
303-
# Step 2: Operator does not operate switch on the DUT
304-
self._placeholder_for_step("2")
305-
self._ask_for_switch_idle()
306-
307-
# Step 3: TH reads the CurrentPosition attribute from the DUT
308-
self._placeholder_for_step("3")
309-
310-
# Verify that the value is 0
311-
current_position = await self.read_single_attribute_check_success(cluster, attribute=cluster.Attributes.CurrentPosition)
312-
asserts.assert_equal(current_position, 0)
313-
314-
# Step 4a: Operator operates switch (keep pressed for long time, e.g. 5 seconds) on the DUT, the release it
315-
self._placeholder_for_step("4a")
316-
self._ask_for_long_press(endpoint_id, switch_pressed_position, feature_map)
317-
318-
# Step 4b: TH expects report of CurrentPosition 1, followed by a report of Current Position 0.
319-
self._placeholder_for_step("4b")
320-
logging.info(
321-
f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for CurrentPosition to go {switch_pressed_position}, then 0.")
322-
self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.CurrentPosition, sequence=[
323-
switch_pressed_position, 0], timeout_sec=post_prompt_settle_delay_seconds)
324-
325-
# Step 4c: TH expects at least InitialPress with NewPosition = 1
326-
self._placeholder_for_step("4c")
327-
logging.info(f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for InitialPress event.")
328-
expected_events = [cluster.Events.InitialPress(newPosition=switch_pressed_position)]
329-
self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id,
330-
sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds)
331-
332-
# Step 4d: For MSL/AS, expect to see LongPress/LongRelease in that order
333-
if not has_msl_feature and not has_as_feature:
334-
logging.info("Skipping Step 4d due to missing MSL and AS features")
335-
self._placeholder_for_skip("4d")
336-
else:
337-
# Steb 4d: TH expects report of LongPress, LongRelease in that order.
338-
self._placeholder_for_step("4d")
339-
logging.info(f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for LongPress then LongRelease.")
340-
expected_events = []
341-
expected_events.append(cluster.Events.LongPress(newPosition=switch_pressed_position))
342-
expected_events.append(cluster.Events.LongRelease(previousPosition=switch_pressed_position))
343-
self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id,
344-
sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds)
345-
346-
# Step 4e: For MS & (!MSL & !AS & !MSR), expect no further events for 10 seconds.
347-
if not has_msl_feature and not has_as_feature and not has_msr_feature:
348-
self._placeholder_for_step("4e")
349-
self._expect_no_events_for_cluster(event_queue=event_listener.event_queue,
350-
endpoint_id=endpoint_id, expected_cluster=cluster, timeout_sec=10.0)
351-
352-
# Step 4f: For MSR & not MSL, expect to see ShortRelease.
353-
if not has_msl_feature and has_msr_feature:
354-
self._placeholder_for_step("4f")
355-
expected_events = [cluster.Events.ShortRelease(previousPosition=switch_pressed_position)]
356-
self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id,
357-
sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds)
358-
359270
def _received_event(self, event_listener: EventChangeCallback, target_event: ClusterObjects.ClusterEvent, timeout_s: int) -> bool:
360271
"""
361272
Returns true if this event was received, false otherwise
@@ -534,6 +445,104 @@ async def test_TC_SWTCH_2_3(self):
534445
button_val = await self.read_single_attribute_check_success(cluster=cluster, attribute=cluster.Attributes.CurrentPosition)
535446
asserts.assert_equal(button_val, 0, "Button value is not 0")
536447

448+
def desc_TC_SWTCH_2_4(self) -> str:
449+
return "[TC-SWTCH-2.4] Momentary Switch Long Press Verification"
450+
451+
def steps_TC_SWTCH_2_4(self):
452+
return [TestStep(1, test_plan_support.commission_if_required(), "", is_commissioning=True),
453+
TestStep(2, "Set up subscription to all events of Switch cluster on the endpoint"),
454+
TestStep(3, "Operator does not operate switch on the DUT"),
455+
TestStep(4, "TH reads the CurrentPosition attribute from the DUT", "Verify that the value is 0"),
456+
TestStep(5, "Operator operates switch (keep pressed for long time, e.g. 5 seconds) on the DUT, the release it",
457+
"""
458+
* TH expects receiving a subscription report of CurrentPosition 1, followed by a report of Current Position 0.
459+
* TH expects receiving at InitialPress event with NewPosition = 1.
460+
* if MSL or AS feature is supported, TH expect receiving LongPress/LongRelease in that order.
461+
* if MS & (!MSL & !AS & !MSR) features present, TH expects receiving no further events for 10 seconds after release.
462+
* if (MSR & !MSL) features present, TH expects receiving ShortRelease event.
463+
""")
464+
]
465+
466+
@per_endpoint_test(has_feature(Clusters.Switch, Clusters.Switch.Bitmaps.Feature.kMomentarySwitch))
467+
async def test_TC_SWTCH_2_4(self):
468+
switch_pressed_position = self._default_pressed_position
469+
post_prompt_settle_delay_seconds = 10.0
470+
471+
endpoint_id = self.matter_test_config.endpoint
472+
cluster = Clusters.Objects.Switch
473+
474+
# Step 1: Commission DUT - already done
475+
self.step(1)
476+
477+
# Read feature map to set bool markers
478+
feature_map = await self.read_single_attribute_check_success(cluster, attribute=cluster.Attributes.FeatureMap)
479+
480+
has_ms_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitch) != 0
481+
has_msr_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitchRelease) != 0
482+
has_msl_feature = (feature_map & cluster.Bitmaps.Feature.kMomentarySwitchLongPress) != 0
483+
has_as_feature = (feature_map & cluster.Bitmaps.Feature.kActionSwitch) != 0
484+
485+
if not has_ms_feature:
486+
logging.info("Skipping rest of test: SWTCH.S.F01(MS) feature not present")
487+
self.skip_all_remaining_steps("2")
488+
489+
# Step 2: Set up subscription to all events of Switch cluster on the endpoint
490+
self.step(2)
491+
event_listener = EventChangeCallback(cluster)
492+
attrib_listener = ClusterAttributeChangeAccumulator(cluster)
493+
await event_listener.start(self.default_controller, self.dut_node_id, endpoint=endpoint_id)
494+
await attrib_listener.start(self.default_controller, self.dut_node_id, endpoint=endpoint_id)
495+
496+
# Step 3: Operator does not operate switch on the DUT
497+
self.step(3)
498+
self._ask_for_switch_idle()
499+
500+
# Step 4: TH reads the CurrentPosition attribute from the DUT
501+
self.step(4)
502+
503+
# Verify that the value is 0
504+
current_position = await self.read_single_attribute_check_success(cluster, attribute=cluster.Attributes.CurrentPosition)
505+
asserts.assert_equal(current_position, 0)
506+
507+
# Step 5: Operator operates switch (keep pressed for long time, e.g. 5 seconds) on the DUT, the release it
508+
self.step(5)
509+
self._ask_for_long_press(endpoint_id, switch_pressed_position, feature_map)
510+
511+
# - TH expects report of CurrentPosition 1, followed by a report of Current Position 0.
512+
logging.info(
513+
f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for CurrentPosition to go {switch_pressed_position}, then 0.")
514+
self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.CurrentPosition, sequence=[
515+
switch_pressed_position, 0], timeout_sec=post_prompt_settle_delay_seconds)
516+
517+
# - TH expects at least InitialPress with NewPosition = 1
518+
logging.info(f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for InitialPress event.")
519+
expected_events = [cluster.Events.InitialPress(newPosition=switch_pressed_position)]
520+
self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id,
521+
sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds)
522+
523+
# - if MSL or AS feature is supported, expect to see LongPress/LongRelease in that order.
524+
if not has_msl_feature and not has_as_feature:
525+
logging.info("Since MSL and AS features both unsupported, skipping check for LongPress/LongRelease")
526+
else:
527+
# - TH expects report of LongPress, LongRelease in that order.
528+
logging.info(f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for LongPress then LongRelease.")
529+
expected_events = []
530+
expected_events.append(cluster.Events.LongPress(newPosition=switch_pressed_position))
531+
expected_events.append(cluster.Events.LongRelease(previousPosition=switch_pressed_position))
532+
self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id,
533+
sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds)
534+
535+
# - if MS & (!MSL & !AS & !MSR) features present, expect no further events for 10 seconds after release.
536+
if not has_msl_feature and not has_as_feature and not has_msr_feature:
537+
self._expect_no_events_for_cluster(event_queue=event_listener.event_queue,
538+
endpoint_id=endpoint_id, expected_cluster=cluster, timeout_sec=10.0)
539+
540+
# - if (MSR & !MSL) features present, expect to see ShortRelease event.
541+
if not has_msl_feature and has_msr_feature:
542+
expected_events = [cluster.Events.ShortRelease(previousPosition=switch_pressed_position)]
543+
self._await_sequence_of_events(event_queue=event_listener.event_queue, endpoint_id=endpoint_id,
544+
sequence=expected_events, timeout_sec=post_prompt_settle_delay_seconds)
545+
537546
def steps_TC_SWTCH_2_5(self):
538547
return [TestStep(1, test_plan_support.commission_if_required(), "", is_commissioning=True),
539548
TestStep(2, "Set up a subscription to all Switch cluster events"),
@@ -638,7 +647,7 @@ async def test_TC_SWTCH_2_5(self):
638647
multi_press_max = await self.read_single_attribute_check_success(cluster, attribute=cluster.Attributes.MultiPressMax)
639648

640649
endpoint_id = self.matter_test_config.endpoint
641-
pressed_position = 1
650+
pressed_position = self._default_pressed_position
642651

643652
self.step(2)
644653
event_listener = EventChangeCallback(cluster)
@@ -657,35 +666,35 @@ def test_multi_press_sequence(starting_step: str, count: int, short_long: bool =
657666
else:
658667
self._ask_for_multi_press(endpoint_id, number_of_presses=count, pressed_position=pressed_position,
659668
feature_map=feature_map, multi_press_max=multi_press_max)
660-
for i in range(count):
669+
for pos_idx in range(count):
661670
event = event_listener.wait_for_event_report(cluster.Events.InitialPress)
662671
asserts.assert_equal(event.newPosition, pressed_position, "Unexpected NewPosition on InitialEvent")
663-
if i > 0:
672+
if pos_idx > 0:
664673
event = event_listener.wait_for_event_report(cluster.Events.MultiPressOngoing)
665674
asserts.assert_equal(event.newPosition, pressed_position, "Unexpected NewPosition on MultiPressOngoing")
666-
asserts.assert_equal(event.currentNumberOfPressesCounted, i+1,
675+
asserts.assert_equal(event.currentNumberOfPressesCounted, pos_idx + 1,
667676
"Unexpected CurrentNumberOfPressesCounted on MultiPressOngoing")
668677
event = event_listener.wait_for_event_report(cluster.Events.ShortRelease)
669678
asserts.assert_equal(event.previousPosition, pressed_position, "Unexpected PreviousPosition on ShortRelease")
670679

671-
step = step[:-1] + chr(ord(step[-1])+1)
680+
step = bump_substep(step)
672681
self.step(step)
673682
self._ask_for_switch_idle()
674683
event = event_listener.wait_for_event_report(cluster.Events.MultiPressComplete)
675684
asserts.assert_equal(event.previousPosition, pressed_position, "Unexpected PreviousPosition on MultiPressComplete")
676685
asserts.assert_equal(event.totalNumberOfPressesCounted, count, "Unexpected count on MultiPressComplete")
677686

678-
test_multi_press_sequence("4a", 1)
687+
test_multi_press_sequence("4a", count=1)
679688

680-
test_multi_press_sequence("5a", 2)
689+
test_multi_press_sequence("5a", count=2)
681690

682691
self.step("6a")
683692
multi_press_max = await self.read_single_attribute_check_success(cluster=cluster, attribute=cluster.Attributes.MultiPressMax)
684693
if multi_press_max == 2:
685694
self.skip_step("6b")
686695
self.skip_step("6c")
687696
else:
688-
test_multi_press_sequence("6b", 3)
697+
test_multi_press_sequence("6b", count=3)
689698

690699
if not has_msl_feature:
691700
self.skip_all_remaining_steps(7)
@@ -694,7 +703,7 @@ def test_multi_press_sequence(starting_step: str, count: int, short_long: bool =
694703
self.step(7)
695704
# subscription is already set up
696705

697-
test_multi_press_sequence("8a", 2, short_long=True)
706+
test_multi_press_sequence("8a", count=2, short_long=True)
698707

699708
self.step("9a")
700709
self._ask_for_multi_press_long_short(endpoint_id, pressed_position, feature_map)
@@ -813,7 +822,7 @@ async def test_TC_SWTCH_2_6(self):
813822
multi_press_max = await self.read_single_attribute_check_success(cluster, attribute=cluster.Attributes.MultiPressMax)
814823

815824
endpoint_id = self.matter_test_config.endpoint
816-
pressed_position = 1
825+
pressed_position = self._default_pressed_position
817826

818827
self.step(2)
819828
event_listener = EventChangeCallback(cluster)
@@ -836,19 +845,19 @@ def test_multi_press_sequence(starting_step: str, count: int, short_long: bool =
836845
event = event_listener.wait_for_event_report(cluster.Events.InitialPress)
837846
asserts.assert_equal(event.newPosition, pressed_position, "Unexpected NewPosition on InitialEvent")
838847

839-
step = step[:-1] + chr(ord(step[-1])+1)
848+
step = bump_substep(step)
840849
self.step(step)
841850
self._ask_for_switch_idle()
842851
event = event_listener.wait_for_event_report(cluster.Events.MultiPressComplete)
843852
asserts.assert_equal(event.previousPosition, pressed_position, "Unexpected PreviousPosition on MultiPressComplete")
844853
expected_count = 0 if count > multi_press_max else count
845854
asserts.assert_equal(event.totalNumberOfPressesCounted, expected_count, "Unexpected count on MultiPressComplete")
846855

847-
test_multi_press_sequence("4a", 1)
856+
test_multi_press_sequence("4a", count=1)
848857

849-
test_multi_press_sequence("5a", 2)
858+
test_multi_press_sequence("5a", count=2)
850859

851-
test_multi_press_sequence("6a", multi_press_max + 1)
860+
test_multi_press_sequence("6a", count=(multi_press_max + 1))
852861

853862
self.step("7a")
854863
if not has_msl_feature:
@@ -857,7 +866,7 @@ def test_multi_press_sequence(starting_step: str, count: int, short_long: bool =
857866
# subscription is already established
858867
self.step("7b")
859868

860-
test_multi_press_sequence("8a", 2, short_long=True)
869+
test_multi_press_sequence("8a", count=2, short_long=True)
861870

862871
self.step("9a")
863872
self._ask_for_multi_press_long_short(endpoint_id, pressed_position, feature_map)

0 commit comments

Comments
 (0)