/* * * Copyright (c) 2020 Project CHIP Authors * Copyright (c) 2016-2017 Nest Labs, Inc. * 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. */ /** * @file * Unit tests for the Chip Persisted Storage API. * */ #include #include #include #include #include #include #include using namespace chip; namespace { TEST(TestPersistedCounter, TestOutOfBox) { TestPersistentStorageDelegate storage; PersistedCounter counter; // When initializing the first time out of the box, we should have a count of 0 and a value of 0x10000 for the next starting // value in persistent storage. EXPECT_EQ(counter.Init(&storage, DefaultStorageKeyAllocator::IMEventNumber(), 0x10000), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), 0ULL); } TEST(TestPersistedCounter, TestReboot) { chip::TestPersistentStorageDelegate storage; chip::PersistedCounter counter, counter2; // When initializing the first time out of the box, we should have a count of 0. EXPECT_EQ(counter.Init(&storage, chip::DefaultStorageKeyAllocator::IMEventNumber(), 0x10000), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), 0ULL); // Now we "reboot", and we should get a count of 0x10000. EXPECT_EQ(counter2.Init(&storage, chip::DefaultStorageKeyAllocator::IMEventNumber(), 0x10000), CHIP_NO_ERROR); EXPECT_EQ(counter2.GetValue(), 0x10000ULL); } TEST(TestPersistedCounter, TestkWriteNextCounterStart) { chip::TestPersistentStorageDelegate storage; chip::PersistedCounter counter; uint64_t storedValue = 0; uint16_t size = sizeof(storedValue); // When initializing the first time out of the box, we should have a count of 0. EXPECT_EQ(counter.Init(&storage, chip::DefaultStorageKeyAllocator::IMEventNumber(), 0x10000), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), 0ULL); // Check new Epoch value was persisted EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(0x10000ULL, storedValue); // Verify that we write out the next starting counter value after // we've exhausted the counter's range. for (int32_t i = 0; i < 0x10000; i++) { EXPECT_EQ(counter.Advance(), CHIP_NO_ERROR); } EXPECT_EQ(counter.GetValue(), 0x10000ULL); // Check new Epoch value was persisted EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(0x20000ULL, storedValue); for (int32_t i = 0; i < 0x10000; i++) { EXPECT_EQ(counter.Advance(), CHIP_NO_ERROR); } EXPECT_EQ(counter.GetValue(), 0x20000ULL); // Check new Epoch value was persisted EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(0x30000ULL, storedValue); } TEST(TestPersistedCounter, TestAdvanceMaxCounterValue) { chip::TestPersistentStorageDelegate storage; chip::PersistedCounter counter; uint8_t storedValue = 0; uint16_t size = sizeof(storedValue); // When initializing the first time out of the box, we should have a count of 0. EXPECT_EQ(counter.Init(&storage, chip::DefaultStorageKeyAllocator::IMEventNumber(), 1U), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), 0); for (uint16_t i = 0; i < UINT8_MAX; i++) { // Make sure we can increment to max value without error EXPECT_EQ(counter.Advance(), CHIP_NO_ERROR); } EXPECT_EQ(counter.GetValue(), 255); // Check new Epoch value was persisted EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(storedValue, 0); // Increment one more step to make sure counter continues to increment EXPECT_EQ(counter.Advance(), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), 0); } TEST(TestPersistedCounter, TestAdvanceBy) { chip::TestPersistentStorageDelegate storage; chip::PersistedCounter counter; // Test values constexpr uint64_t startingEpochValue = 65535; constexpr uint64_t newValue = 2 * startingEpochValue + 156; constexpr uint64_t newEpochValue = newValue + startingEpochValue; uint64_t storedValue = 0; uint16_t size = sizeof(storedValue); // When initializing the first time out of the box, we should have a count of 0. EXPECT_EQ(counter.Init(&storage, chip::DefaultStorageKeyAllocator::IMEventNumber(), startingEpochValue), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), 0ULL); // Set New value EXPECT_EQ(counter.AdvanceBy(newValue), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), newValue); // Check new Epoch value was persisted EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(newEpochValue, storedValue); } TEST(TestPersistedCounter, TestAdvanceByMaxCounterValue) { chip::TestPersistentStorageDelegate storage; chip::PersistedCounter counter; uint64_t storedValue = 0; uint16_t size = sizeof(storedValue); EXPECT_EQ(counter.Init(&storage, chip::DefaultStorageKeyAllocator::IMEventNumber(), 1ULL), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), 0ULL); EXPECT_EQ(counter.AdvanceBy(UINT64_MAX), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), UINT64_MAX); // Check new Epoch value was persisted EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(0ULL, storedValue); // Increment one more step to make sure counter continues to increment EXPECT_EQ(counter.AdvanceBy(1ULL), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), 0ULL); } TEST(TestPersistedCounter, TestAdvanceByRollover) { chip::TestPersistentStorageDelegate storage; chip::PersistedCounter counter; uint64_t epoch = UINT64_MAX / 4; uint64_t currentEpoch = epoch; uint64_t current = 0; uint64_t storedValue = 0; uint16_t size = sizeof(storedValue); EXPECT_EQ(counter.Init(&storage, chip::DefaultStorageKeyAllocator::IMEventNumber(), epoch), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), current); // Check new Epoch value was persisted EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(currentEpoch, storedValue); // Increase counter to update persisted value current += (currentEpoch + 100); EXPECT_EQ(counter.AdvanceBy(currentEpoch + 100), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), current); // Check new Epoch value was persisted currentEpoch = (currentEpoch * 2 + 100); EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(currentEpoch, storedValue); // Force roll over current += (3 * epoch); EXPECT_EQ(counter.AdvanceBy((3 * epoch)), CHIP_NO_ERROR); EXPECT_EQ(counter.GetValue(), current); // Check new Epoch value was persisted currentEpoch = current + epoch; EXPECT_EQ(storage.SyncGetKeyValue(chip::DefaultStorageKeyAllocator::IMEventNumber().KeyName(), &storedValue, size), CHIP_NO_ERROR); EXPECT_EQ(sizeof(storedValue), size); storedValue = Encoding::LittleEndian::HostSwap(storedValue); EXPECT_EQ(currentEpoch, storedValue); } } // namespace