blob: 65630049e1978e4b08d81146463d8751fd7a520d [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <string.h>
#include <algorithm>
#include <memory>
#include <vector>
#include <lib/ftl-mtd/ftl-volume-wrapper.h>
#include <lib/ftl-mtd/nand-volume-driver.h>
#include <lib/mtd/mtd-interface.h>
#include <zxtest/zxtest.h>
using namespace ftl_mtd;
// FtlVolumeWrapperIntegrationTest relies on a device file located at /dev/mtd0/
// On the host machine, nandsim is used to create a virtual MTD device.
// The following command was used to create the device for this test.
// $ sudo modprobe nandsim id_bytes=0x2c,0xdc,0x90,0xa6,0x54,0x0 badblocks=5
namespace {
constexpr const char* kTestDevicePath = "/dev/mtd0";
constexpr uint32_t kBlockOffset = 0;
constexpr uint32_t kMaxBadBlocks = 10;
class FtlVolumeWrapperIntegrationTest : public zxtest::Test {
protected:
void SetUp() override {
ftl_volume_wrapper_ = std::make_unique<FtlVolumeWrapper>();
auto mtd_interface = mtd::MtdInterface::Create(kTestDevicePath);
interface_ = mtd_interface.get();
WipeNandInterface();
std::unique_ptr<NandVolumeDriver> nand_volume_driver;
ASSERT_OK(NandVolumeDriver::Create(kBlockOffset, kMaxBadBlocks, std::move(mtd_interface),
&nand_volume_driver));
ASSERT_NULL(nand_volume_driver->Init());
ASSERT_OK(ftl_volume_wrapper_->Init(std::move(nand_volume_driver)));
}
void WipeNandInterface() {
uint32_t size = interface_->Size();
uint32_t block_size = interface_->BlockSize();
for (uint32_t block_offset = 0; block_offset < size; block_offset += block_size) {
bool is_bad_block;
ASSERT_OK(interface_->IsBadBlock(block_offset, &is_bad_block));
if (!is_bad_block) {
ASSERT_OK(interface_->EraseBlock(block_offset));
}
}
}
mtd::NandInterface* interface_;
std::unique_ptr<FtlVolumeWrapper> ftl_volume_wrapper_;
};
TEST_F(FtlVolumeWrapperIntegrationTest, ReadWriteSucceeds) {
uint32_t page_count = 2;
uint32_t byte_count = page_count * interface_->PageSize();
uint32_t seek_offset = 15 * interface_->BlockSize();
std::vector<uint8_t> buffer(byte_count);
// Wrapper should always start at 0.
ASSERT_EQ(0, ftl_volume_wrapper_->Tell());
// 1. Write one set of values.
memset(buffer.data(), 0xAB, byte_count);
ASSERT_EQ(byte_count, ftl_volume_wrapper_->Write(buffer.data(), byte_count));
ASSERT_EQ(byte_count, ftl_volume_wrapper_->Tell());
// 2. Write a different set of values.
memset(buffer.data(), 0xCD, byte_count);
ASSERT_EQ(byte_count, ftl_volume_wrapper_->Write(buffer.data(), byte_count));
ASSERT_EQ(2 * byte_count, ftl_volume_wrapper_->Tell());
// 3. Seek to a different place and write yet another different set of values.
ASSERT_EQ(seek_offset, ftl_volume_wrapper_->Seek(seek_offset, SEEK_SET));
memset(buffer.data(), 0x1F, byte_count);
ASSERT_EQ(byte_count, ftl_volume_wrapper_->Write(buffer.data(), byte_count));
ASSERT_EQ(seek_offset + byte_count, ftl_volume_wrapper_->Tell());
ASSERT_OK(ftl_volume_wrapper_->Sync());
// Read back the bytes and ensure they're what we expect.
ASSERT_EQ(0, ftl_volume_wrapper_->Seek(0, SEEK_SET));
memset(buffer.data(), 0, byte_count);
ASSERT_EQ(byte_count, ftl_volume_wrapper_->Read(buffer.data(), byte_count));
ASSERT_TRUE(std::all_of(buffer.begin(), buffer.end(), [](uint8_t val) { return val == 0xAB; }));
ASSERT_EQ(byte_count, ftl_volume_wrapper_->Tell());
memset(buffer.data(), 0, byte_count);
ASSERT_EQ(byte_count, ftl_volume_wrapper_->Read(buffer.data(), byte_count));
ASSERT_TRUE(std::all_of(buffer.begin(), buffer.end(), [](uint8_t val) { return val == 0xCD; }));
ASSERT_EQ(2 * byte_count, ftl_volume_wrapper_->Tell());
ASSERT_EQ(seek_offset, ftl_volume_wrapper_->Seek(seek_offset, SEEK_SET));
memset(buffer.data(), 0, byte_count);
ASSERT_EQ(byte_count, ftl_volume_wrapper_->Read(buffer.data(), byte_count));
ASSERT_TRUE(std::all_of(buffer.begin(), buffer.end(), [](uint8_t val) { return val == 0x1F; }));
ASSERT_EQ(seek_offset + byte_count, ftl_volume_wrapper_->Tell());
}
} // namespace