diff --git a/examples/thermostat/linux/include/thermostat-delegate-impl.h b/examples/thermostat/linux/include/thermostat-delegate-impl.h index 8252f2274f9d79..281c09ad3a1a63 100644 --- a/examples/thermostat/linux/include/thermostat-delegate-impl.h +++ b/examples/thermostat/linux/include/thermostat-delegate-impl.h @@ -33,12 +33,16 @@ namespace Thermostat { * */ -static constexpr uint8_t kMaxNumberOfPresetTypes = 6; +static constexpr uint8_t kMaxNumberOfPresetTypes = 7; // TODO: #34556 Support multiple presets of each type. // We will support only one preset of each preset type. static constexpr uint8_t kMaxNumberOfPresetsOfEachType = 1; +// The number of presets supported is set to a value equal to than (kMaxNumberOfPresetTypes * kMaxNumberOfPresetsOfEachType) - 1 +// for testing purposes. +static constexpr uint8_t kMaxNumberOfPresets = kMaxNumberOfPresetTypes * kMaxNumberOfPresetsOfEachType - 1; + class ThermostatDelegate : public Delegate { public: @@ -90,7 +94,11 @@ class ThermostatDelegate : public Delegate uint8_t mNumberOfPresets; Structs::PresetTypeStruct::Type mPresetTypes[kMaxNumberOfPresetTypes]; - PresetStructWithOwnedMembers mPresets[kMaxNumberOfPresetTypes * kMaxNumberOfPresetsOfEachType]; + PresetStructWithOwnedMembers mPresets[kMaxNumberOfPresets]; + + // For testing purposes, we have a pending presets array that matches the size of PresetTypes so it can + // accomodate a preset of each type including UserDefined for the case where total number of presets + // exceeds number of presets supported. PresetStructWithOwnedMembers mPendingPresets[kMaxNumberOfPresetTypes * kMaxNumberOfPresetsOfEachType]; uint8_t mNextFreeIndexInPendingPresetsList; diff --git a/examples/thermostat/linux/thermostat-delegate-impl.cpp b/examples/thermostat/linux/thermostat-delegate-impl.cpp index c39a757a8b0644..6c17fcf3c96876 100644 --- a/examples/thermostat/linux/thermostat-delegate-impl.cpp +++ b/examples/thermostat/linux/thermostat-delegate-impl.cpp @@ -32,7 +32,8 @@ ThermostatDelegate ThermostatDelegate::sInstance; ThermostatDelegate::ThermostatDelegate() { - mNumberOfPresets = kMaxNumberOfPresetTypes * kMaxNumberOfPresetsOfEachType; + static_assert(kMaxNumberOfPresets <= kMaxNumberOfPresetTypes * kMaxNumberOfPresetsOfEachType); + mNumberOfPresets = kMaxNumberOfPresets; mNextFreeIndexInPresetsList = 0; mNextFreeIndexInPendingPresetsList = 0; @@ -47,7 +48,8 @@ void ThermostatDelegate::InitializePresetTypes() { PresetScenarioEnum presetScenarioEnumArray[kMaxNumberOfPresetTypes] = { PresetScenarioEnum::kOccupied, PresetScenarioEnum::kUnoccupied, PresetScenarioEnum::kSleep, - PresetScenarioEnum::kWake, PresetScenarioEnum::kVacation, PresetScenarioEnum::kGoingToSleep + PresetScenarioEnum::kWake, PresetScenarioEnum::kVacation, PresetScenarioEnum::kGoingToSleep, + PresetScenarioEnum::kUserDefined }; static_assert(ArraySize(presetScenarioEnumArray) <= ArraySize(mPresetTypes)); diff --git a/src/python_testing/TC_TSTAT_4_2.py b/src/python_testing/TC_TSTAT_4_2.py index 5c289ced50604e..85b16e10486517 100644 --- a/src/python_testing/TC_TSTAT_4_2.py +++ b/src/python_testing/TC_TSTAT_4_2.py @@ -186,6 +186,10 @@ def steps_TC_TSTAT_4_2(self) -> list[TestStep]: "Verify that the write request is rejected"), TestStep("16", "TH starts an atomic write, and before it's complete, TH2 removes TH's fabric; TH2 then opens an atomic write", "Verify that the atomic request is successful"), + TestStep("17", "TH writes to the Presets attribute with a preset that has a presetScenario not present in PresetTypes attribute", + "Verify that the write request returned CONSTRAINT_ERROR (0x87)."), + TestStep("18", "TH writes to the Presets attribute such that the total number of presets is greater than the number of presets supported", + "Verify that the AtomicRequest commit returned RESOURCE_EXHAUSTED (0x89)."), ] return steps @@ -441,8 +445,44 @@ async def test_TC_TSTAT_4_2(self): # Roll back await self.send_atomic_request_rollback_command() - # TODO: Add tests for the total number of Presets exceeds the NumberOfPresets supported. Also Add tests for adding presets with preset scenario not present in PresetTypes. + self.step("17") + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.Cfe.Rsp")): + test_presets = new_presets_with_handle.copy() + test_presets.append(cluster.Structs.PresetStruct(presetHandle=NullValue, presetScenario=9, + name="Wake", coolingSetpoint=2500, heatingSetpoint=1700, builtIn=False)) + + # Send the AtomicRequest begin command + await self.send_atomic_request_begin_command() + + await self.write_presets(endpoint=endpoint, presets=test_presets, expected_status=Status.ConstraintError) + + # Clear state for next test. + await self.send_atomic_request_rollback_command() + + self.step("18") + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.Cfe.Rsp")): + + # Read the active preset handle attribute and verify it was updated to preset handle + presetTypes = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=cluster.Attributes.PresetTypes) + logger.info(f"Rx'd PresetTypes: {presetTypes}") + + test_presets = copy.deepcopy(new_presets_with_handle) + test_presets.append(cluster.Structs.PresetStruct(presetHandle=NullValue, presetScenario=cluster.Enums.PresetScenarioEnum.kWake, + name="Wake", coolingSetpoint=2500, heatingSetpoint=1700, builtIn=False)) + test_presets.append(cluster.Structs.PresetStruct(presetHandle=NullValue, presetScenario=cluster.Enums.PresetScenarioEnum.kVacation, + name="Vacation", coolingSetpoint=2400, heatingSetpoint=1800, builtIn=False)) + test_presets.append(cluster.Structs.PresetStruct(presetHandle=NullValue, presetScenario=cluster.Enums.PresetScenarioEnum.kGoingToSleep, + name="GoingToSleep", coolingSetpoint=2300, heatingSetpoint=1900, builtIn=False)) + test_presets.append(cluster.Structs.PresetStruct(presetHandle=NullValue, presetScenario=cluster.Enums.PresetScenarioEnum.kUserDefined, + name="UserDefined", coolingSetpoint=2300, heatingSetpoint=1900, builtIn=False)) + + # Send the AtomicRequest begin command + await self.send_atomic_request_begin_command() + + await self.write_presets(endpoint=endpoint, presets=test_presets) + # Send the AtomicRequest commit command and expect ResourceExhausted for presets. + await self.send_atomic_request_commit_command(expected_overall_status=Status.Failure, expected_preset_status=Status.ResourceExhausted) if __name__ == "__main__": default_matter_test_main()