| // 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 "inspector/parser.h" |
| |
| #include <blobfs/format.h> |
| #include <storage/buffer/array_buffer.h> |
| #include <fs/transaction/block_transaction.h> |
| #include <zxtest/zxtest.h> |
| |
| namespace blobfs { |
| namespace { |
| |
| TEST(InspectorParser, ParseSuperblock) { |
| uint64_t start_block = 0; |
| uint64_t block_length = 1; |
| Superblock superblock; |
| superblock.magic0 = kBlobfsMagic0; |
| superblock.magic1 = kBlobfsMagic1; |
| superblock.alloc_block_count = 1234; |
| |
| storage::ArrayBuffer device(block_length, kBlobfsBlockSize); |
| auto device_sb = reinterpret_cast<Superblock*>(device.Data(start_block)); |
| *device_sb = superblock; |
| |
| Superblock out_superblock = GetSuperblock(&device); |
| ASSERT_EQ(superblock.magic0, out_superblock.magic0); |
| ASSERT_EQ(superblock.magic1, out_superblock.magic1); |
| ASSERT_EQ(superblock.blob_header_next, out_superblock.blob_header_next); |
| ASSERT_EQ(superblock.alloc_block_count, out_superblock.alloc_block_count); |
| } |
| |
| TEST(InspectorParser, ParseBitmap) { |
| uint32_t start_block = 0; |
| uint32_t block_length = 1; |
| storage::ArrayBuffer device(block_length, kBlobfsBlockSize); |
| memset(device.Data(start_block), 0xAA, device.capacity() * device.BlockSize()); |
| |
| for (uint32_t i = 0; i < block_length * kBlobfsBlockSize * CHAR_BIT; ++i) { |
| ASSERT_EQ(i % 2 != 0, GetBitmapElement(&device, i)); |
| } |
| } |
| |
| TEST(InspectorParser, ParseInodeTable) { |
| uint32_t block_length = 2; |
| storage::ArrayBuffer device(block_length, kBlobfsBlockSize); |
| |
| uint32_t expected_block_count = 42; |
| uint32_t inode_count = 0; |
| for (uint32_t block_offset = 0; block_offset < block_length; ++block_offset) { |
| auto inodes = reinterpret_cast<Inode*>(device.Data(block_offset)); |
| for (uint32_t inode_offset = 0; inode_offset < kBlobfsInodesPerBlock; ++inode_offset) { |
| inodes[inode_offset].blob_size = inode_count; |
| inodes[inode_offset].block_count = expected_block_count; |
| inode_count++; |
| } |
| } |
| for (uint32_t i = 0; i < inode_count; ++i) { |
| Inode out_inode = GetInodeElement(&device, i); |
| ASSERT_EQ(i, out_inode.blob_size); |
| ASSERT_EQ(expected_block_count, out_inode.block_count); |
| } |
| } |
| |
| TEST(InspectorParser, WriteBitmapElement) { |
| uint32_t start_block = 0; |
| uint32_t block_length = 1; |
| storage::ArrayBuffer device(block_length, kBlobfsBlockSize); |
| memset(device.Data(start_block), 0xFF, device.capacity() * device.BlockSize()); |
| |
| for (uint32_t i = 0; i < block_length * kBlobfsBlockSize * CHAR_BIT; ++i) { |
| ASSERT_TRUE(GetBitmapElement(&device, i)); |
| } |
| |
| // Write the |write_element| bit to false. |
| uint64_t write_element = 25; |
| bool write_value = false; |
| WriteBitmapElement(&device, write_value, write_element); |
| |
| for (uint32_t i = 0; i < block_length * kBlobfsBlockSize * CHAR_BIT; ++i) { |
| bool is_set = (i == write_element) ? write_value : !write_value; |
| ASSERT_EQ(is_set, GetBitmapElement(&device, i)); |
| } |
| |
| // Write the bit back to true. |
| WriteBitmapElement(&device, true, write_element); |
| |
| for (uint32_t i = 0; i < block_length * kBlobfsBlockSize * CHAR_BIT; ++i) { |
| ASSERT_TRUE(GetBitmapElement(&device, i)); |
| } |
| } |
| |
| TEST(InspectorParser, WriteSingleInodeElement) { |
| uint32_t block_length = 2; |
| storage::ArrayBuffer device(block_length, kBlobfsBlockSize); |
| memset(device.Data(0), 0x00, block_length * kBlobfsBlockSize); |
| |
| uint32_t expected_block_count = 42; |
| uint32_t inode_count = block_length * kBlobfsInodesPerBlock; |
| |
| // Sanity check zeroed out ok. |
| for (uint32_t i = 0; i < inode_count; ++i) { |
| Inode out_inode = GetInodeElement(&device, i); |
| ASSERT_EQ(0, out_inode.blob_size); |
| ASSERT_EQ(0, out_inode.block_count); |
| } |
| |
| // Test writing a single inode. |
| Inode inode = {}; |
| inode.blob_size = 0; |
| inode.block_count = expected_block_count; |
| WriteInodeElement(&device, inode, 0); |
| Inode out_inode = GetInodeElement(&device, 0); |
| |
| ASSERT_EQ(inode.blob_size, out_inode.blob_size); |
| ASSERT_EQ(inode.block_count, out_inode.block_count); |
| |
| // Make sure rest of device is not set. |
| for (uint64_t i = 1; i < inode_count; ++i) { |
| Inode out_inode = GetInodeElement(&device, i); |
| ASSERT_EQ(0, out_inode.blob_size); |
| ASSERT_EQ(0, out_inode.block_count); |
| } |
| } |
| |
| TEST(InspectorParser, WriteManyInodeElements) { |
| uint32_t block_length = 2; |
| storage::ArrayBuffer device(block_length, kBlobfsBlockSize); |
| memset(device.Data(0), 0x00, block_length * kBlobfsBlockSize); |
| |
| uint32_t expected_block_count = 42; |
| uint32_t inode_count = block_length * kBlobfsInodesPerBlock; |
| |
| // Sanity check zeroed out ok. |
| for (uint32_t i = 0; i < inode_count; ++i) { |
| Inode out_inode = GetInodeElement(&device, i); |
| ASSERT_EQ(0, out_inode.blob_size); |
| ASSERT_EQ(0, out_inode.block_count); |
| } |
| |
| // Test setting all the inodes. |
| for (uint64_t i = 0; i < inode_count; ++i) { |
| Inode inode = {}; |
| inode.blob_size = i; |
| inode.block_count = expected_block_count; |
| WriteInodeElement(&device, inode, i); |
| } |
| for (uint64_t i = 0; i < inode_count; ++i) { |
| Inode out_inode = GetInodeElement(&device, i); |
| ASSERT_EQ(i, out_inode.blob_size); |
| ASSERT_EQ(expected_block_count, out_inode.block_count); |
| } |
| } |
| |
| } // namespace |
| } // namespace blobfs |