blob: 8d0babc9a7f9d4fe531bf3d49326acda5605fa7a [file] [log] [blame]
// Copyright 2020 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 "fs/transaction/buffered_operations_builder.h"
#include <gtest/gtest.h>
#include <storage/buffer/vmo_buffer.h>
#include <storage/buffer/vmoid_registry.h>
namespace {
using fs::BufferedOperationsBuilder;
using storage::Operation;
using storage::OperationType;
using storage::VmoBuffer;
using storage::VmoidRegistry;
const vmoid_t kVmoid1 = 5;
const vmoid_t kVmoid2 = 12;
const size_t kCapacity = 3;
const uint32_t kBlockSize = 8192;
constexpr char kLabel[] = "test-vmo";
TEST(BufferedOperationsBuilderTest, NoRequest) {
BufferedOperationsBuilder builder;
auto requests = builder.TakeOperations();
EXPECT_TRUE(requests.empty());
}
class MockVmoidRegistry : public VmoidRegistry {
public:
MockVmoidRegistry(vmoid_t vmoid = kVmoid1) : vmoid_(vmoid) {}
zx_status_t BlockAttachVmo(const zx::vmo& vmo, storage::Vmoid* out) final {
*out = storage::Vmoid(vmoid_);
return ZX_OK;
}
zx_status_t BlockDetachVmo(storage::Vmoid vmoid) final {
EXPECT_EQ(vmoid_, vmoid.TakeId());
return ZX_OK;
}
private:
vmoid_t vmoid_;
};
TEST(BufferedOperationsBuilderTest, OneRequest) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry;
VmoBuffer buffer;
buffer.Initialize(&registry, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kWrite;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer);
auto requests = builder.TakeOperations();
ASSERT_EQ(1u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(OperationType::kWrite, requests[0].op.type);
EXPECT_EQ(operation.vmo_offset, requests[0].op.vmo_offset);
EXPECT_EQ(operation.dev_offset, requests[0].op.dev_offset);
EXPECT_EQ(operation.length, requests[0].op.length);
}
TEST(BufferedOperationsBuilderTest, TwoRequestDifferentVmo) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry_1;
VmoBuffer buffer_1;
buffer_1.Initialize(&registry_1, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kWrite;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer_1);
MockVmoidRegistry registry_2(kVmoid2);
VmoBuffer buffer_2;
buffer_2.Initialize(&registry_2, kCapacity, kBlockSize, kLabel);
operation.vmo_offset = 1;
operation.dev_offset = 1;
builder.Add(operation, &buffer_2);
auto requests = builder.TakeOperations();
ASSERT_EQ(2u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(kVmoid2, requests[1].vmoid);
EXPECT_EQ(OperationType::kWrite, requests[0].op.type);
EXPECT_EQ(OperationType::kWrite, requests[1].op.type);
EXPECT_EQ(0u, requests[0].op.vmo_offset);
EXPECT_EQ(0u, requests[0].op.dev_offset);
EXPECT_EQ(1u, requests[0].op.length);
EXPECT_EQ(1u, requests[1].op.vmo_offset);
EXPECT_EQ(1u, requests[1].op.dev_offset);
EXPECT_EQ(1u, requests[1].op.length);
}
TEST(BufferedOperationsBuilderTest, TwoRequestMergeOperations) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry;
VmoBuffer buffer;
buffer.Initialize(&registry, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kWrite;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer);
operation.vmo_offset = 1;
operation.dev_offset = 1;
builder.Add(operation, &buffer);
auto requests = builder.TakeOperations();
ASSERT_EQ(1u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(OperationType::kWrite, requests[0].op.type);
EXPECT_EQ(0u, requests[0].op.vmo_offset);
EXPECT_EQ(0u, requests[0].op.dev_offset);
EXPECT_EQ(2u, requests[0].op.length);
}
TEST(BufferedOperationsBuilderTest, TwoRequestDifferentType) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry;
VmoBuffer buffer;
buffer.Initialize(&registry, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kWrite;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer);
operation.type = OperationType::kRead;
operation.vmo_offset = 1;
operation.dev_offset = 1;
builder.Add(operation, &buffer);
auto requests = builder.TakeOperations();
ASSERT_EQ(2u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(kVmoid1, requests[1].vmoid);
EXPECT_EQ(OperationType::kWrite, requests[0].op.type);
EXPECT_EQ(OperationType::kRead, requests[1].op.type);
EXPECT_EQ(0u, requests[0].op.vmo_offset);
EXPECT_EQ(0u, requests[0].op.dev_offset);
EXPECT_EQ(1u, requests[0].op.length);
EXPECT_EQ(1u, requests[1].op.vmo_offset);
EXPECT_EQ(1u, requests[1].op.dev_offset);
EXPECT_EQ(1u, requests[1].op.length);
}
TEST(BufferedOperationsBuilderTest, TwoRequestVmoGap) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry;
VmoBuffer buffer;
buffer.Initialize(&registry, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kWrite;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer);
operation.vmo_offset = 2;
operation.dev_offset = 1;
builder.Add(operation, &buffer);
auto requests = builder.TakeOperations();
ASSERT_EQ(2u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(kVmoid1, requests[1].vmoid);
EXPECT_EQ(OperationType::kWrite, requests[0].op.type);
EXPECT_EQ(OperationType::kWrite, requests[1].op.type);
EXPECT_EQ(0u, requests[0].op.vmo_offset);
EXPECT_EQ(0u, requests[0].op.dev_offset);
EXPECT_EQ(1u, requests[0].op.length);
EXPECT_EQ(2u, requests[1].op.vmo_offset);
EXPECT_EQ(1u, requests[1].op.dev_offset);
EXPECT_EQ(1u, requests[1].op.length);
}
TEST(BufferedOperationsBuilderTest, TwoRequestDeviceGap) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry;
VmoBuffer buffer;
buffer.Initialize(&registry, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kWrite;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer);
operation.vmo_offset = 1;
operation.dev_offset = 2;
builder.Add(operation, &buffer);
auto requests = builder.TakeOperations();
ASSERT_EQ(2u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(kVmoid1, requests[1].vmoid);
EXPECT_EQ(OperationType::kWrite, requests[0].op.type);
EXPECT_EQ(OperationType::kWrite, requests[1].op.type);
EXPECT_EQ(0u, requests[0].op.vmo_offset);
EXPECT_EQ(0u, requests[0].op.dev_offset);
EXPECT_EQ(1u, requests[0].op.length);
EXPECT_EQ(1u, requests[1].op.vmo_offset);
EXPECT_EQ(2u, requests[1].op.dev_offset);
EXPECT_EQ(1u, requests[1].op.length);
}
TEST(BufferedOperationsBuilderTest, TwoRequestReplaceOperation) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry;
VmoBuffer buffer;
buffer.Initialize(&registry, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kRead;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer);
operation.length = 2;
builder.Add(operation, &buffer);
auto requests = builder.TakeOperations();
ASSERT_EQ(1u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(OperationType::kRead, requests[0].op.type);
EXPECT_EQ(0u, requests[0].op.vmo_offset);
EXPECT_EQ(0u, requests[0].op.dev_offset);
EXPECT_EQ(2u, requests[0].op.length);
}
TEST(BufferedOperationsBuilderTest, TwoRequestDifferentDeviceOffset) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry;
VmoBuffer buffer;
buffer.Initialize(&registry, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kRead;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer);
operation.length = 2;
operation.dev_offset = 2;
builder.Add(operation, &buffer);
auto requests = builder.TakeOperations();
ASSERT_EQ(2u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(kVmoid1, requests[1].vmoid);
EXPECT_EQ(OperationType::kRead, requests[0].op.type);
EXPECT_EQ(OperationType::kRead, requests[1].op.type);
EXPECT_EQ(0u, requests[0].op.vmo_offset);
EXPECT_EQ(0u, requests[0].op.dev_offset);
EXPECT_EQ(1u, requests[0].op.length);
EXPECT_EQ(0u, requests[1].op.vmo_offset);
EXPECT_EQ(2u, requests[1].op.dev_offset);
EXPECT_EQ(2u, requests[1].op.length);
}
TEST(BufferedOperationsBuilderTest, TwoRequestDifferentVmoOffset) {
BufferedOperationsBuilder builder;
MockVmoidRegistry registry;
VmoBuffer buffer;
buffer.Initialize(&registry, kCapacity, kBlockSize, kLabel);
Operation operation;
operation.type = OperationType::kRead;
operation.vmo_offset = 0;
operation.dev_offset = 0;
operation.length = 1;
builder.Add(operation, &buffer);
operation.length = 2;
operation.vmo_offset = 2;
builder.Add(operation, &buffer);
auto requests = builder.TakeOperations();
ASSERT_EQ(2u, requests.size());
EXPECT_EQ(kVmoid1, requests[0].vmoid);
EXPECT_EQ(kVmoid1, requests[1].vmoid);
EXPECT_EQ(OperationType::kRead, requests[0].op.type);
EXPECT_EQ(OperationType::kRead, requests[1].op.type);
EXPECT_EQ(0u, requests[0].op.vmo_offset);
EXPECT_EQ(0u, requests[0].op.dev_offset);
EXPECT_EQ(1u, requests[0].op.length);
EXPECT_EQ(2u, requests[1].op.vmo_offset);
EXPECT_EQ(0u, requests[1].op.dev_offset);
EXPECT_EQ(2u, requests[1].op.length);
}
} // namespace