blob: 186415105d4a2872a876a9c58278ae1debb45bf2 [file] [log] [blame]
/*
*
* Copyright (c) 2025 Project CHIP Authors
* All rights reserved.
*
* 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.
*/
#include <app-common/zap-generated/cluster-enums.h>
#include <pw_unit_test/framework.h>
#include <app/icd/server/ICDConfigurationData.h>
#include <app/icd/server/tests/ICDConfigurationDataTestAccess.h>
#include <lib/core/StringBuilderAdapters.h>
#include <lib/support/TimeUtils.h>
#include <lib/support/tests/ExtraPwTestMacros.h>
#include <messaging/tests/MessagingContext.h>
#include <system/SystemLayerImpl.h>
using namespace chip;
using namespace chip::Testing;
using namespace chip::app;
using namespace chip::System;
using namespace chip::System::Clock;
using namespace chip::System::Clock::Literals;
namespace {} // namespace
namespace chip {
namespace app {
class TestICDConfigurationData : public LoopbackMessagingContext
{
public:
// Performs shared setup for all tests in the test suite
static void SetUpTestSuite()
{
LoopbackMessagingContext::SetUpTestSuite();
VerifyOrReturn(!HasFailure());
ASSERT_EQ(chip::DeviceLayer::PlatformMgr().InitChipStack(), CHIP_NO_ERROR);
}
// Performs shared teardown for all tests in the test suite
static void TearDownTestSuite()
{
DeviceLayer::SetSystemLayerForTesting(nullptr);
DeviceLayer::PlatformMgr().Shutdown();
LoopbackMessagingContext::TearDownTestSuite();
}
// Performs setup for each individual test in the test suite
void SetUp() override
{
LoopbackMessagingContext::SetUp();
VerifyOrReturn(!HasFailure());
}
// Performs teardown for each individual test in the test suite
void TearDown() override { LoopbackMessagingContext::TearDown(); }
};
TEST_F(TestICDConfigurationData, TestICDModeSwitching)
{
auto & configData = ICDConfigurationData::GetInstance();
Testing::ICDConfigurationDataTestAccess privateConfigData(&configData);
// Default mode should be SIT
EXPECT_EQ(configData.GetICDMode(), ICDConfigurationData::ICDMode::SIT);
// Switch to LIT and check
privateConfigData.SetICDMode(ICDConfigurationData::ICDMode::LIT);
EXPECT_EQ(configData.GetICDMode(), ICDConfigurationData::ICDMode::LIT);
// Switch back to SIT and check
privateConfigData.SetICDMode(ICDConfigurationData::ICDMode::SIT);
EXPECT_EQ(configData.GetICDMode(), ICDConfigurationData::ICDMode::SIT);
}
TEST_F(TestICDConfigurationData, TestSetSITPollingInterval)
{
Testing::ICDConfigurationDataTestAccess privateConfigData(&ICDConfigurationData::GetInstance());
System::Clock::Milliseconds32 validSITPollInterval(10000);
System::Clock::Milliseconds32 invalidSITPollInterval =
privateConfigData.GetSitSlowPollMaximum() + System::Clock::Milliseconds32(1000); // Above SIT threshold
// Should succeed for valid value
EXPECT_EQ(privateConfigData.SetSITPollingInterval(validSITPollInterval), CHIP_NO_ERROR);
// Should fail for invalid value
EXPECT_EQ(privateConfigData.SetSITPollingInterval(invalidSITPollInterval), CHIP_ERROR_INVALID_ARGUMENT);
}
TEST_F(TestICDConfigurationData, TestGetAndSetSlowPollingInterval)
{
auto & configData = ICDConfigurationData::GetInstance();
Testing::ICDConfigurationDataTestAccess privateConfigData(&configData);
// Set featuremap to include LIT support
using Feature = Clusters::IcdManagement::Feature;
BitFlags<Feature> featureMap;
featureMap.Set(Feature::kLongIdleTimeSupport);
privateConfigData.SetFeatureMap(featureMap);
// Set a ICD SIT Slow Poll Interval
System::Clock::Milliseconds32 SITPollInterval(10000);
EXPECT_EQ(privateConfigData.SetSITPollingInterval(SITPollInterval), CHIP_NO_ERROR);
// Set operation mode to LIT and confirm mode
privateConfigData.SetICDMode(ICDConfigurationData::ICDMode::LIT);
EXPECT_EQ(configData.GetICDMode(), ICDConfigurationData::ICDMode::LIT);
// Set a slow polling interval of 60s, used in LIT mode and verify
System::Clock::Milliseconds32 newInterval(60000);
EXPECT_EQ(privateConfigData.SetSlowPollingInterval(newInterval), CHIP_NO_ERROR);
// In LIT mode Standard SlowPollingInterval is always used
EXPECT_EQ(configData.GetSlowPollingInterval(), newInterval);
// Switch operation mode to SIT and confirm mode
privateConfigData.SetICDMode(ICDConfigurationData::ICDMode::SIT);
EXPECT_EQ(configData.GetICDMode(), ICDConfigurationData::ICDMode::SIT);
// In SIT mode The shortest interval between SlowPollingInterval and SITPollingInterval is used
// In this case the the SITPollInterval interval is used
EXPECT_EQ(configData.GetSlowPollingInterval(), SITPollInterval);
// Reduce slow polling interval to 5s, shorter than SITPollingInterval
System::Clock::Milliseconds32 shortSlowPollInterval(5000);
EXPECT_SUCCESS(privateConfigData.SetSlowPollingInterval(shortSlowPollInterval));
EXPECT_EQ(privateConfigData.SetSlowPollingInterval(shortSlowPollInterval), CHIP_NO_ERROR);
EXPECT_EQ(configData.GetSlowPollingInterval(), shortSlowPollInterval);
// Switch operation mode to LIT and confirm mode
privateConfigData.SetICDMode(ICDConfigurationData::ICDMode::LIT);
EXPECT_EQ(configData.GetICDMode(), ICDConfigurationData::ICDMode::LIT);
// slow polling interval remains in use
EXPECT_EQ(configData.GetSlowPollingInterval(), shortSlowPollInterval);
// increase slow polling interval to 20s, longer than SITPollingInterval
System::Clock::Milliseconds32 longerSlowPollInterval(20000);
EXPECT_EQ(privateConfigData.SetSlowPollingInterval(longerSlowPollInterval), CHIP_NO_ERROR);
// longerSlowPollInterval is used
EXPECT_EQ(configData.GetSlowPollingInterval(), longerSlowPollInterval);
// Switch operation mode to SIT and confirm mode
privateConfigData.SetICDMode(ICDConfigurationData::ICDMode::SIT);
EXPECT_EQ(configData.GetICDMode(), ICDConfigurationData::ICDMode::SIT);
// SIT Polling Interval is used
EXPECT_EQ(configData.GetSlowPollingInterval(), SITPollInterval);
featureMap.Clear(Feature::kLongIdleTimeSupport);
privateConfigData.SetFeatureMap(featureMap);
// Without LIT support, the slow polling interval cannot bet set greater than the SIT polling threshold
EXPECT_EQ(privateConfigData.SetSlowPollingInterval(longerSlowPollInterval), CHIP_ERROR_INVALID_ARGUMENT);
// Set a Valid Slow Polling Interval greater than the SIT Polling Interval
System::Clock::Milliseconds32 validSlowPollInterval(12000);
EXPECT_EQ(privateConfigData.SetSlowPollingInterval(validSlowPollInterval), CHIP_NO_ERROR);
// Without LIT support, the slow polling interval is used and the SIT Polling Interval value is not taken into account
EXPECT_EQ(configData.GetSlowPollingInterval(), validSlowPollInterval);
}
TEST_F(TestICDConfigurationData, TestSetModeDurations)
{
auto & configData = ICDConfigurationData::GetInstance();
Testing::ICDConfigurationDataTestAccess privateConfigData(&configData);
using namespace System::Clock;
// Save original values
Seconds32 origIdle = configData.GetIdleModeDuration();
Milliseconds32 origActive = configData.GetActiveModeDuration();
// Set valid durations
Milliseconds32 newActive(2000);
Seconds32 newIdle(10);
EXPECT_EQ(privateConfigData.SetModeDurations(MakeOptional(newActive), MakeOptional(Milliseconds32(newIdle.count() * 1000))),
CHIP_NO_ERROR);
EXPECT_EQ(configData.GetActiveModeDuration(), newActive);
EXPECT_EQ(configData.GetIdleModeDuration(), newIdle);
// Set invalid: active > idle
EXPECT_EQ(privateConfigData.SetModeDurations(MakeOptional(Milliseconds32(20000)), MakeOptional(Milliseconds32(1000))),
CHIP_ERROR_INVALID_ARGUMENT);
// Test SetModeDurations with shortIdleModeDuration
// Valid all three params: active=1500ms, idle=8s, shortIdle=3s
EXPECT_EQ(privateConfigData.SetModeDurations(std::optional<Milliseconds32>(Milliseconds32(1500)),
std::optional<Seconds32>(Seconds32(8)), std::optional<Seconds32>(Seconds32(3))),
CHIP_NO_ERROR);
// Invalid: shortIdle > idle (6s > 5s)
EXPECT_EQ(privateConfigData.SetModeDurations(std::optional<Milliseconds32>(Milliseconds32(1500)),
std::optional<Seconds32>(Seconds32(5)), std::optional<Seconds32>(Seconds32(6))),
CHIP_ERROR_INVALID_ARGUMENT);
// Omit shortIdle: idle shrinks below previous shortIdle, shortIdle should clamp to new idle (=> equal, so not used)
EXPECT_EQ(privateConfigData.SetModeDurations(std::optional<Milliseconds32>(Milliseconds32(1500)),
std::optional<Seconds32>(Seconds32(2)), std::nullopt),
CHIP_NO_ERROR);
// Provide only shortIdle (smaller than current idle=2s is not possible to be <2s unless 1s)
EXPECT_EQ(privateConfigData.SetModeDurations(std::nullopt, std::nullopt, std::optional<Seconds32>(Seconds32(1))),
CHIP_NO_ERROR);
// Error: none provided
EXPECT_EQ(privateConfigData.SetModeDurations(std::nullopt, std::nullopt, std::nullopt), CHIP_ERROR_INVALID_ARGUMENT);
// Error: active > idle with 3-param API
EXPECT_EQ(privateConfigData.SetModeDurations(std::optional<Milliseconds32>(Milliseconds32(9000)),
std::optional<Seconds32>(Seconds32(5)), std::optional<Seconds32>(Seconds32(3))),
CHIP_ERROR_INVALID_ARGUMENT);
// Restore original values
EXPECT_EQ(privateConfigData.SetModeDurations(MakeOptional(origActive), MakeOptional(Milliseconds32(origIdle.count() * 1000))),
CHIP_NO_ERROR);
}
} // namespace app
} // namespace chip