blob: 774a6f8be90d2d7a73c4964fb25d596f3ba616ef [file] [log] [blame]
// Copyright 2021 The Pigweed 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
//
// https://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 "pw_blob_store/flat_file_system_entry.h"
#include <array>
#include <cstddef>
#include <cstring>
#include "gtest/gtest.h"
#include "pw_blob_store/blob_store.h"
#include "pw_kvs/crc16_checksum.h"
#include "pw_kvs/fake_flash_memory.h"
#include "pw_kvs/flash_memory.h"
#include "pw_kvs/test_key_value_store.h"
#include "pw_random/xor_shift.h"
#include "pw_span/span.h"
#include "pw_sync/mutex.h"
namespace pw::blob_store {
namespace {
class FlatFileSystemBlobStoreEntryTest : public ::testing::Test {
protected:
static constexpr char kBlobTitle[] = "TestBlobBlock";
static constexpr size_t kBufferSize = 64;
FlatFileSystemBlobStoreEntryTest()
: flash_(kFlashAlignment),
partition_(&flash_),
metadata_buffer_(),
source_buffer_(),
checksum_(),
blob_(kBlobTitle, partition_, &checksum_, kvs::TestKvs(), kBufferSize) {
}
void SetUp() override { ASSERT_EQ(OkStatus(), blob_.Init()); }
void InitSourceBufferToRandom(uint64_t seed,
size_t init_size_bytes = kBlobDataSize) {
ASSERT_LE(init_size_bytes, source_buffer_.size());
random::XorShiftStarRng64 rng(seed);
std::memset(source_buffer_.data(),
static_cast<int>(flash_.erased_memory_content()),
source_buffer_.size());
ASSERT_EQ(OkStatus(),
rng.Get(span(source_buffer_).first(init_size_bytes)).status());
}
// Fill the source buffer with random pattern based on given seed, written to
// BlobStore in specified chunk size.
void WriteTestBlock(std::string_view file_name, size_t write_size_bytes) {
ASSERT_LE(write_size_bytes, source_buffer_.size());
ConstByteSpan write_data = span(source_buffer_).first(write_size_bytes);
BlobStore::BlobWriter writer(blob_, metadata_buffer_);
EXPECT_EQ(OkStatus(), writer.Open());
ASSERT_EQ(OkStatus(), writer.SetFileName(file_name));
ASSERT_EQ(OkStatus(), writer.Write(write_data));
EXPECT_EQ(OkStatus(), writer.Close());
// Use reader to check for valid data.
BlobStore::BlobReader reader(blob_);
ASSERT_EQ(OkStatus(), reader.Open());
Result<ConstByteSpan> result = reader.GetMemoryMappedBlob();
ASSERT_TRUE(result.ok());
EXPECT_EQ(write_size_bytes, result.value().size_bytes());
EXPECT_EQ(OkStatus(), reader.Close());
}
static constexpr size_t kFlashAlignment = 16;
static constexpr size_t kSectorSize = 2048;
static constexpr size_t kSectorCount = 2;
static constexpr size_t kBlobDataSize = (kSectorCount * kSectorSize);
static constexpr size_t kMaxFileNameLength = 32;
static constexpr size_t kMetadataBufferSize =
BlobStore::BlobWriter::RequiredMetadataBufferSize(kMaxFileNameLength);
kvs::FakeFlashMemoryBuffer<kSectorSize, kSectorCount> flash_;
kvs::FlashPartition partition_;
std::array<std::byte, kMetadataBufferSize> metadata_buffer_;
std::array<std::byte, kBlobDataSize> source_buffer_;
kvs::ChecksumCrc16 checksum_;
BlobStoreBuffer<kBufferSize> blob_;
};
TEST_F(FlatFileSystemBlobStoreEntryTest, BasicProperties) {
constexpr size_t kWrittenDataSizeBytes = 104;
constexpr uint32_t kExpectedFileId = 0x731ACAC0;
constexpr FlatFileSystemBlobStoreEntry::FilePermissions kExpectedPermissions =
FlatFileSystemBlobStoreEntry::FilePermissions::READ;
constexpr std::string_view kFileName("my_file_1.bin");
InitSourceBufferToRandom(0x5C4CA189);
WriteTestBlock(kFileName, kWrittenDataSizeBytes);
std::array<char, kMaxFileNameLength> tmp_buffer = {};
static_assert(kFileName.size() <= tmp_buffer.size());
sync::VirtualMutex blob_store_mutex;
FlatFileSystemBlobStoreEntry blob_store_file(
kExpectedFileId, kExpectedPermissions, blob_, blob_store_mutex);
StatusWithSize sws = blob_store_file.Name(tmp_buffer);
ASSERT_EQ(OkStatus(), sws.status());
const int comparison =
memcmp(tmp_buffer.data(), kFileName.data(), sws.size());
EXPECT_EQ(0, comparison);
EXPECT_EQ(kWrittenDataSizeBytes, blob_store_file.SizeBytes());
EXPECT_EQ(kExpectedPermissions, blob_store_file.Permissions());
EXPECT_EQ(kExpectedFileId, blob_store_file.FileId());
}
TEST_F(FlatFileSystemBlobStoreEntryTest, Delete) {
constexpr size_t kWrittenDataSizeBytes = 104;
constexpr uint32_t kExpectedFileId = 0x87ED0EF2;
constexpr FlatFileSystemBlobStoreEntry::FilePermissions kExpectedPermissions =
FlatFileSystemBlobStoreEntry::FilePermissions::READ;
constexpr std::string_view kFileName("my_file_1.bin");
InitSourceBufferToRandom(0x5C4CA189);
WriteTestBlock(kFileName, kWrittenDataSizeBytes);
sync::VirtualMutex blob_store_mutex;
FlatFileSystemBlobStoreEntry blob_store_file(
kExpectedFileId, kExpectedPermissions, blob_, blob_store_mutex);
ASSERT_EQ(OkStatus(), blob_store_file.Delete());
BlobStore::BlobReader reader(blob_);
// Failed precondition is the expected return value when a BlobStore is opened
// for reading and is empty.
ASSERT_EQ(Status::FailedPrecondition(), reader.Open());
}
TEST_F(FlatFileSystemBlobStoreEntryTest, NoData) {
constexpr uint32_t kExpectedFileId = 0x1;
constexpr FlatFileSystemBlobStoreEntry::FilePermissions kExpectedPermissions =
FlatFileSystemBlobStoreEntry::FilePermissions::READ;
// Ensure the BlobStore is erased.
ASSERT_EQ(OkStatus(), partition_.Erase());
sync::VirtualMutex blob_store_mutex;
FlatFileSystemBlobStoreEntry blob_store_file(
kExpectedFileId, kExpectedPermissions, blob_, blob_store_mutex);
std::array<char, kMaxFileNameLength> tmp_buffer = {};
StatusWithSize sws = blob_store_file.Name(tmp_buffer);
EXPECT_EQ(Status::NotFound(), sws.status());
EXPECT_EQ(0u, sws.size());
}
} // namespace
} // namespace pw::blob_store