/* * * Copyright (c) 2020-2022 Project CHIP Authors * * 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. */ /** * @file * This file implements a unit test suite for the Configuration Manager * code functionality. * */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace chip; using namespace chip::Logging; using namespace chip::Inet; using namespace chip::DeviceLayer; namespace { // ================================= // Unit tests // ================================= struct TestConfigurationMgr : ::testing::Test { static void SetUpTestSuite() { // ConfigurationManager is initialized from PlatformManager indirectly CHIP_ERROR err = chip::Platform::MemoryInit(); EXPECT_EQ(err, CHIP_NO_ERROR); err = PlatformMgr().InitChipStack(); EXPECT_EQ(err, CHIP_NO_ERROR); } static void TearDownTestSuite() { PlatformMgr().Shutdown(); chip::Platform::MemoryShutdown(); } }; TEST_F(TestConfigurationMgr, RunUnitTest) { #if CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK // TODO: Fix RunUnitTests() for Open IOT SDK. // Previously, TestPlatformMgr_RunUnitTest was only run if !NDEBUG while the Open IOT SDK // test runner was built with NDEBUG set. return; #endif ConfigurationMgr().RunUnitTests(); } TEST_F(TestConfigurationMgr, SerialNumber) { CHIP_ERROR err = CHIP_NO_ERROR; char buf[64]; const char * serialNumber = "89051AAZZ236"; err = ConfigurationMgr().StoreSerialNumber(serialNumber, strlen(serialNumber)); EXPECT_EQ(err, CHIP_NO_ERROR); err = GetDeviceInstanceInfoProvider()->GetSerialNumber(buf, 64); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strlen(buf), 12u); EXPECT_STREQ(buf, serialNumber); err = ConfigurationMgr().StoreSerialNumber(serialNumber, 5); EXPECT_EQ(err, CHIP_NO_ERROR); err = GetDeviceInstanceInfoProvider()->GetSerialNumber(buf, 64); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strlen(buf), 5u); EXPECT_STREQ(buf, "89051"); } TEST_F(TestConfigurationMgr, UniqueId) { CHIP_ERROR err = CHIP_NO_ERROR; char buf[64]; const char * uniqueId = "67MXAZ012RT8UE"; err = ConfigurationMgr().StoreUniqueId(uniqueId, strlen(uniqueId)); EXPECT_EQ(err, CHIP_NO_ERROR); err = ConfigurationMgr().GetUniqueId(buf, 64); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strlen(buf), 14u); EXPECT_STREQ(buf, uniqueId); err = ConfigurationMgr().StoreUniqueId(uniqueId, 7); EXPECT_EQ(err, CHIP_NO_ERROR); err = ConfigurationMgr().GetUniqueId(buf, 64); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strlen(buf), 7u); EXPECT_STREQ(buf, "67MXAZ0"); } TEST_F(TestConfigurationMgr, ManufacturingDate) { CHIP_ERROR err = CHIP_NO_ERROR; const char * mfgDate = "2008/09/20"; uint16_t year; uint8_t month; uint8_t dayOfMonth; err = ConfigurationMgr().StoreManufacturingDate(mfgDate, strlen(mfgDate)); EXPECT_EQ(err, CHIP_NO_ERROR); err = GetDeviceInstanceInfoProvider()->GetManufacturingDate(year, month, dayOfMonth); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(year, 2008); EXPECT_EQ(month, 9); EXPECT_EQ(dayOfMonth, 20); } TEST_F(TestConfigurationMgr, HardwareVersion) { CHIP_ERROR err = CHIP_NO_ERROR; uint16_t hardwareVer; err = ConfigurationMgr().StoreHardwareVersion(1234); EXPECT_EQ(err, CHIP_NO_ERROR); err = GetDeviceInstanceInfoProvider()->GetHardwareVersion(hardwareVer); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(hardwareVer, 1234); } static int SnprintfBuildDate(char * s, size_t n, uint16_t year, uint8_t month, uint8_t day) { // Print the calendar date to a human readable string as would // given from the __DATE__ macro. const char * monthString = nullptr; switch (month) { case 1: monthString = "Jan"; break; case 2: monthString = "Feb"; break; case 3: monthString = "Mar"; break; case 4: monthString = "Apr"; break; case 5: monthString = "May"; break; case 6: monthString = "Jun"; break; case 7: monthString = "Jul"; break; case 8: monthString = "Aug"; break; case 9: monthString = "Sep"; break; case 10: monthString = "Oct"; break; case 11: monthString = "Nov"; break; case 12: monthString = "Dec"; break; } if (monthString == nullptr) { return -1; } return snprintf(s, n, "%s %2u %u", monthString, day, year); } static int SnprintfBuildDate(char * s, size_t n, System::Clock::Seconds32 chipEpochBuildTime) { // Convert to a calendar date-time. uint16_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; ChipEpochToCalendarTime(chipEpochBuildTime.count(), year, month, day, hour, minute, second); return SnprintfBuildDate(s, n, year, month, day); } static int SnprintfBuildTimeOfDay(char * s, size_t n, uint8_t hour, uint8_t minute, uint8_t second) { // Print the time of day to a human readable string as would // given from the __TIME__ macro. return snprintf(s, n, "%02u:%02u:%02u", hour, minute, second); } static int SnprintfBuildTimeOfDay(char * s, size_t n, System::Clock::Seconds32 chipEpochBuildTime) { // Convert to a calendar date-time. uint16_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; ChipEpochToCalendarTime(chipEpochBuildTime.count(), year, month, day, hour, minute, second); return SnprintfBuildTimeOfDay(s, n, hour, minute, second); } TEST_F(TestConfigurationMgr, FirmwareBuildTime) { // Read the firmware build time from the configuration manager. // This is referenced to the CHIP epoch. System::Clock::Seconds32 chipEpochTime; EXPECT_EQ(ConfigurationMgr().GetFirmwareBuildChipEpochTime(chipEpochTime), CHIP_NO_ERROR); // Override the hard-coded build time with the setter and verify operation. System::Clock::Seconds32 overrideValue = System::Clock::Seconds32(rand()); EXPECT_EQ(ConfigurationMgr().SetFirmwareBuildChipEpochTime(overrideValue), CHIP_NO_ERROR); EXPECT_EQ(ConfigurationMgr().GetFirmwareBuildChipEpochTime(chipEpochTime), CHIP_NO_ERROR); EXPECT_EQ(overrideValue, chipEpochTime); // Verify that the BuildTime.h parser can parse current CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_DATE / TIME. do { const char * date = CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_DATE; const char * timeOfDay = CHIP_DEVICE_CONFIG_FIRMWARE_BUILD_TIME; // Check that strings look good. EXPECT_FALSE(BUILD_DATE_IS_BAD(date)); EXPECT_FALSE(BUILD_TIME_IS_BAD(timeOfDay)); if (BUILD_DATE_IS_BAD(date) || BUILD_TIME_IS_BAD(timeOfDay)) { break; } // Parse. uint16_t year = COMPUTE_BUILD_YEAR(date); uint8_t month = COMPUTE_BUILD_MONTH(date); uint8_t day = COMPUTE_BUILD_DAY(date); uint8_t hour = COMPUTE_BUILD_HOUR(timeOfDay); uint8_t minute = COMPUTE_BUILD_MIN(timeOfDay); uint8_t second = COMPUTE_BUILD_SEC(timeOfDay); // Print the date to a string as would be given by the __DATE__ macro. char parsedDate[14] = { 0 }; // strlen("Jan 000 00000") == 13 { int printed; printed = SnprintfBuildDate(parsedDate, sizeof(parsedDate), year, month, day); EXPECT_GT(printed, 0); EXPECT_LT(printed, static_cast(sizeof(parsedDate))); } // Print the time of day to a straing as would be given by the __TIME__ macro. char parsedTimeOfDay[12] = { 0 }; // strlen("000:000:000") == 11 { int printed; printed = SnprintfBuildTimeOfDay(parsedTimeOfDay, sizeof(parsedTimeOfDay), hour, minute, second); EXPECT_GT(printed, 0); EXPECT_LT(printed, static_cast(sizeof(parsedTimeOfDay))); } // Verify match. EXPECT_STREQ(date, parsedDate); EXPECT_STREQ(timeOfDay, parsedTimeOfDay); } while (false); // Generate random chip epoch times and verify that our BuildTime.h parser // macros also work for these. for (int i = 0; i < 10000; ++i) { char date[14] = { 0 }; // strlen("Jan 000 00000") == 13 char timeOfDay[12] = { 0 }; // strlen("000:000:000") == 11 chipEpochTime = System::Clock::Seconds32(rand()); // rand() will only give us [0, 0x7FFFFFFF]. Give us coverage for // times in the upper half of the chip epoch time range as well. chipEpochTime = i % 2 ? chipEpochTime : System::Clock::Seconds32(chipEpochTime.count() | 0x80000000); // Print the date to a string as would be given by the __DATE__ macro. { int printed; printed = SnprintfBuildDate(date, sizeof(date), chipEpochTime); EXPECT_GT(printed, 0); EXPECT_LT(printed, static_cast(sizeof(date))); } // Print the time of day to a straing as would be given by the __TIME__ macro. { int printed; printed = SnprintfBuildTimeOfDay(timeOfDay, sizeof(timeOfDay), chipEpochTime); EXPECT_GT(printed, 0); EXPECT_LT(printed, static_cast(sizeof(timeOfDay))); } // Check that strings look good. EXPECT_FALSE(BUILD_DATE_IS_BAD(date)); EXPECT_FALSE(BUILD_TIME_IS_BAD(timeOfDay)); if (BUILD_DATE_IS_BAD(date) || BUILD_TIME_IS_BAD(timeOfDay)) { continue; } // Convert from chip epoch seconds to calendar time. uint16_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; ChipEpochToCalendarTime(chipEpochTime.count(), year, month, day, hour, minute, second); // Verify that our BuildTime.h macros can correctly parse the date / time strings. EXPECT_EQ(year, COMPUTE_BUILD_YEAR(date)); EXPECT_EQ(month, COMPUTE_BUILD_MONTH(date)); EXPECT_EQ(day, COMPUTE_BUILD_DAY(date)); EXPECT_EQ(hour, COMPUTE_BUILD_HOUR(timeOfDay)); EXPECT_EQ(minute, COMPUTE_BUILD_MIN(timeOfDay)); EXPECT_EQ(second, COMPUTE_BUILD_SEC(timeOfDay)); } } TEST_F(TestConfigurationMgr, CountryCode) { CHIP_ERROR err = CHIP_NO_ERROR; char buf[8]; size_t countryCodeLen = 0; const char * countryCode = "US"; err = ConfigurationMgr().StoreCountryCode(countryCode, strlen(countryCode)); EXPECT_EQ(err, CHIP_NO_ERROR); err = ConfigurationMgr().GetCountryCode(buf, 8, countryCodeLen); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(countryCodeLen, strlen(countryCode)); EXPECT_STREQ(buf, countryCode); } TEST_F(TestConfigurationMgr, GetPrimaryMACAddress) { CHIP_ERROR err = CHIP_NO_ERROR; uint8_t macBuffer8Bytes[8]; uint8_t macBuffer6Bytes[6]; MutableByteSpan mac8Bytes(macBuffer8Bytes); MutableByteSpan mac6Bytes(macBuffer6Bytes); err = ConfigurationMgr().GetPrimaryMACAddress(mac8Bytes); if (mac8Bytes.size() != ConfigurationManager::kPrimaryMACAddressLength) { EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT); } err = ConfigurationMgr().GetPrimaryMACAddress(mac6Bytes); if (mac6Bytes.size() != ConfigurationManager::kPrimaryMACAddressLength) { EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT); } // NOTICE for above: // no validation for CHIP_NO_ERROR: // - there is no guarantee in CI that a valid IP address exists, // expecially if running in emulators (zephyr and qemu) } TEST_F(TestConfigurationMgr, GetFailSafeArmed) { CHIP_ERROR err = CHIP_NO_ERROR; bool failSafeArmed = false; err = ConfigurationMgr().SetFailSafeArmed(true); EXPECT_EQ(err, CHIP_NO_ERROR); err = ConfigurationMgr().GetFailSafeArmed(failSafeArmed); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(failSafeArmed, true); err = ConfigurationMgr().SetFailSafeArmed(false); EXPECT_EQ(err, CHIP_NO_ERROR); } TEST_F(TestConfigurationMgr, GetVendorName) { CHIP_ERROR err = CHIP_NO_ERROR; char buf[64]; err = GetDeviceInstanceInfoProvider()->GetVendorName(buf, 64); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_GT(strlen(buf), 0u); EXPECT_LE(strlen(buf), ConfigurationManager::kMaxVendorNameLength); } TEST_F(TestConfigurationMgr, GetVendorId) { CHIP_ERROR err = CHIP_NO_ERROR; uint16_t vendorId; err = GetDeviceInstanceInfoProvider()->GetVendorId(vendorId); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_GE(vendorId, 0u); EXPECT_LE(vendorId, 0xfff4); } TEST_F(TestConfigurationMgr, GetProductName) { CHIP_ERROR err = CHIP_NO_ERROR; char buf[64]; err = GetDeviceInstanceInfoProvider()->GetProductName(buf, 64); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_GT(strlen(buf), 0u); EXPECT_LE(strlen(buf), ConfigurationManager::kMaxProductNameLength); } TEST_F(TestConfigurationMgr, GetProductId) { CHIP_ERROR err = CHIP_NO_ERROR; uint16_t productId; err = GetDeviceInstanceInfoProvider()->GetProductId(productId); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_GE(productId, 1u); EXPECT_LE(productId, 0xffff); } } // namespace