Refactor test cases
This commit is contained in:
parent
d63d66c97b
commit
8b792e691c
@ -1,429 +0,0 @@
|
|||||||
#include "DataTreeTest.h"
|
|
||||||
|
|
||||||
#include "../../../../implementations/onblocks/datatreestore/DataTree.h"
|
|
||||||
#include "../../../../implementations/onblocks/datanodestore/DataLeafNode.h"
|
|
||||||
#include "../../../../implementations/onblocks/datanodestore/DataInnerNode.h"
|
|
||||||
#include "../../../testutils/DataBlockFixture.h"
|
|
||||||
|
|
||||||
#include "messmer/cpp-utils/pointer.h"
|
|
||||||
|
|
||||||
using ::testing::WithParamInterface;
|
|
||||||
using ::testing::Values;
|
|
||||||
|
|
||||||
using cpputils::dynamic_pointer_move;
|
|
||||||
|
|
||||||
using blobstore::onblocks::datanodestore::DataNode;
|
|
||||||
using blobstore::onblocks::datanodestore::DataInnerNode;
|
|
||||||
using blobstore::onblocks::datanodestore::DataLeafNode;
|
|
||||||
using blockstore::Key;
|
|
||||||
|
|
||||||
using namespace blobstore::onblocks::datatreestore;
|
|
||||||
|
|
||||||
class DataTreeGrowingTest: public DataTreeTest {
|
|
||||||
public:
|
|
||||||
|
|
||||||
Key CreateTreeAddOneLeafReturnRootKey() {
|
|
||||||
auto tree = CreateLeafOnlyTree();
|
|
||||||
auto key = tree->key();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
Key CreateTreeAddTwoLeavesReturnRootKey() {
|
|
||||||
auto tree = CreateLeafOnlyTree();
|
|
||||||
auto key = tree->key();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
Key CreateTreeAddThreeLeavesReturnRootKey() {
|
|
||||||
auto tree = CreateLeafOnlyTree();
|
|
||||||
auto key = tree->key();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
Key CreateThreeNodeChainedTreeReturnRootKey() {
|
|
||||||
auto leaf = nodeStore.createNewLeafNode();
|
|
||||||
auto node = nodeStore.createNewInnerNode(*leaf);
|
|
||||||
auto root = nodeStore.createNewInnerNode(*node);
|
|
||||||
return root->key();
|
|
||||||
}
|
|
||||||
|
|
||||||
Key CreateThreeLevelTreeWithLowerLevelFullReturnRootKey() {
|
|
||||||
auto leaf = nodeStore.createNewLeafNode();
|
|
||||||
auto node = nodeStore.createNewInnerNode(*leaf);
|
|
||||||
FillNode(node.get());
|
|
||||||
auto root = nodeStore.createNewInnerNode(*node);
|
|
||||||
return root->key();
|
|
||||||
}
|
|
||||||
|
|
||||||
Key CreateThreeLevelTreeWithTwoFullSubtrees() {
|
|
||||||
auto leaf1 = nodeStore.createNewLeafNode();
|
|
||||||
auto leaf2 = nodeStore.createNewLeafNode();
|
|
||||||
auto leaf3 = nodeStore.createNewLeafNode();
|
|
||||||
auto node1 = nodeStore.createNewInnerNode(*leaf1);
|
|
||||||
FillNode(node1.get());
|
|
||||||
auto node2 = nodeStore.createNewInnerNode(*leaf2);
|
|
||||||
FillNode(node2.get());
|
|
||||||
auto root = nodeStore.createNewInnerNode(*node1);
|
|
||||||
root->addChild(*node2);
|
|
||||||
return root->key();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddLeafTo(const Key &key) {
|
|
||||||
DataTree tree(&nodeStore, nodeStore.load(key));
|
|
||||||
tree.addDataLeaf();
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataInnerNode> LoadInnerNode(const Key &key) {
|
|
||||||
auto node = nodeStore.load(key);
|
|
||||||
auto casted = dynamic_pointer_move<DataInnerNode>(node);
|
|
||||||
EXPECT_NE(nullptr, casted.get()) << "Is not an inner node";
|
|
||||||
return casted;
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataLeafNode> LoadLeafNode(const Key &key) {
|
|
||||||
auto node = nodeStore.load(key);
|
|
||||||
auto casted = dynamic_pointer_move<DataLeafNode>(node);
|
|
||||||
EXPECT_NE(nullptr, casted.get()) << "Is not a leaf node";
|
|
||||||
return casted;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_IS_LEAF_NODE(const Key &key) {
|
|
||||||
auto node = LoadLeafNode(key);
|
|
||||||
EXPECT_NE(nullptr, node.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_IS_INNER_NODE(const Key &key) {
|
|
||||||
auto node = LoadInnerNode(key);
|
|
||||||
EXPECT_NE(nullptr, node.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_IS_FULL_TWOLEVEL_TREE(const Key &key) {
|
|
||||||
auto node = LoadInnerNode(key);
|
|
||||||
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
|
|
||||||
for (unsigned int i = 0; i < node->numChildren(); ++i) {
|
|
||||||
EXPECT_IS_LEAF_NODE(node->getChild(i)->key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_IS_FULL_THREELEVEL_TREE(const Key &key) {
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, root->numChildren());
|
|
||||||
for (unsigned int i = 0; i < root->numChildren(); ++i) {
|
|
||||||
auto node = LoadInnerNode(root->getChild(i)->key());
|
|
||||||
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
|
|
||||||
for (unsigned int j = 0; j < node->numChildren(); ++j) {
|
|
||||||
EXPECT_IS_LEAF_NODE(node->getChild(j)->key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_IS_TWONODE_CHAIN(const Key &key) {
|
|
||||||
auto node = LoadInnerNode(key);
|
|
||||||
EXPECT_EQ(1u, node->numChildren());
|
|
||||||
EXPECT_IS_LEAF_NODE(node->getChild(0)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_IS_THREENODE_CHAIN(const Key &key) {
|
|
||||||
auto node1 = LoadInnerNode(key);
|
|
||||||
EXPECT_EQ(1u, node1->numChildren());
|
|
||||||
auto node2 = LoadInnerNode(node1->getChild(0)->key());
|
|
||||||
EXPECT_EQ(1u, node2->numChildren());
|
|
||||||
EXPECT_IS_LEAF_NODE(node2->getChild(0)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(const Key &key) {
|
|
||||||
DataTree tree(&nodeStore, nodeStore.load(key));
|
|
||||||
tree.addDataLeaf();
|
|
||||||
EXPECT_EQ(key, tree.key());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(unsigned int expectedNumberOfLeaves, const Key &key) {
|
|
||||||
auto node = LoadInnerNode(key);
|
|
||||||
EXPECT_EQ(expectedNumberOfLeaves, node->numChildren());
|
|
||||||
for(unsigned int i=0;i<expectedNumberOfLeaves;++i) {
|
|
||||||
EXPECT_IS_LEAF_NODE(node->getChild(i)->key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAOneNodeTree_KeyDoesntChange) {
|
|
||||||
auto key = CreateLeafOnlyTree()->key();
|
|
||||||
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAOneNodeTree_Structure) {
|
|
||||||
auto key = CreateTreeAddOneLeafReturnRootKey();
|
|
||||||
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(2, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAOneNodeTree_FlushingWorks) {
|
|
||||||
//Tests that after calling flush(), the complete grown tree structure is written to the blockstore
|
|
||||||
auto tree = CreateLeafOnlyTree();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->flush();
|
|
||||||
|
|
||||||
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(2, tree->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowATwoNodeTree_KeyDoesntChange) {
|
|
||||||
auto key = CreateTreeAddOneLeafReturnRootKey();
|
|
||||||
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowATwoNodeTree_Structure) {
|
|
||||||
auto key = CreateTreeAddTwoLeavesReturnRootKey();
|
|
||||||
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(3, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowATwoLevelThreeNodeTree_KeyDoesntChange) {
|
|
||||||
auto key = CreateTreeAddTwoLeavesReturnRootKey();
|
|
||||||
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowATwoLevelThreeNodeTree_Structure) {
|
|
||||||
auto key = CreateTreeAddThreeLeavesReturnRootKey();
|
|
||||||
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(4, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAThreeNodeChainedTree_KeyDoesntChange) {
|
|
||||||
auto root_key = CreateThreeNodeChainedTreeReturnRootKey();
|
|
||||||
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAThreeNodeChainedTree_Structure) {
|
|
||||||
auto key = CreateThreeNodeChainedTreeReturnRootKey();
|
|
||||||
AddLeafTo(key);
|
|
||||||
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
EXPECT_EQ(1u, root->numChildren());
|
|
||||||
|
|
||||||
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(2, root->getChild(0)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAThreeLevelTreeWithLowerLevelFull_KeyDoesntChange) {
|
|
||||||
auto root_key = CreateThreeLevelTreeWithLowerLevelFullReturnRootKey();
|
|
||||||
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAThreeLevelTreeWithLowerLevelFull_Structure) {
|
|
||||||
auto root_key = CreateThreeLevelTreeWithLowerLevelFullReturnRootKey();
|
|
||||||
AddLeafTo(root_key);
|
|
||||||
|
|
||||||
auto root = LoadInnerNode(root_key);
|
|
||||||
EXPECT_EQ(2u, root->numChildren());
|
|
||||||
|
|
||||||
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(0)->key());
|
|
||||||
EXPECT_IS_TWONODE_CHAIN(root->getChild(1)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAFullTwoLevelTree_KeyDoesntChange) {
|
|
||||||
auto root_key = CreateFullTwoLevelTree();
|
|
||||||
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAFullTwoLevelTree_Structure) {
|
|
||||||
auto root_key = CreateFullTwoLevelTree();
|
|
||||||
AddLeafTo(root_key);
|
|
||||||
|
|
||||||
auto root = LoadInnerNode(root_key);
|
|
||||||
EXPECT_EQ(2u, root->numChildren());
|
|
||||||
|
|
||||||
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(0)->key());
|
|
||||||
EXPECT_IS_TWONODE_CHAIN(root->getChild(1)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAFullThreeLevelTree_KeyDoesntChange) {
|
|
||||||
auto root_key = CreateFullThreeLevelTree();
|
|
||||||
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAFullThreeLevelTree_Structure) {
|
|
||||||
auto root_key = CreateFullThreeLevelTree();
|
|
||||||
AddLeafTo(root_key);
|
|
||||||
|
|
||||||
auto root = LoadInnerNode(root_key);
|
|
||||||
EXPECT_EQ(2u, root->numChildren());
|
|
||||||
|
|
||||||
EXPECT_IS_FULL_THREELEVEL_TREE(root->getChild(0)->key());
|
|
||||||
EXPECT_IS_THREENODE_CHAIN(root->getChild(1)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAThreeLevelTreeWithTwoFullSubtrees_KeyDoesntChange) {
|
|
||||||
auto root_key = CreateThreeLevelTreeWithTwoFullSubtrees();
|
|
||||||
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingTest, GrowAThreeLevelTreeWithTwoFullSubtrees_Structure) {
|
|
||||||
auto root_key = CreateThreeLevelTreeWithTwoFullSubtrees();
|
|
||||||
AddLeafTo(root_key);
|
|
||||||
|
|
||||||
auto root = LoadInnerNode(root_key);
|
|
||||||
EXPECT_EQ(3u, root->numChildren());
|
|
||||||
|
|
||||||
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(0)->key());
|
|
||||||
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(1)->key());
|
|
||||||
EXPECT_IS_TWONODE_CHAIN(root->getChild(2)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
class LeafDataFixture {
|
|
||||||
public:
|
|
||||||
LeafDataFixture(int size, int iv = 0): _data(size, iv) {}
|
|
||||||
|
|
||||||
void FillInto(DataLeafNode *leaf) const {
|
|
||||||
leaf->resize(_data.size());
|
|
||||||
std::memcpy(leaf->data(), _data.data(), _data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_DATA_CORRECT(const DataLeafNode &leaf) const {
|
|
||||||
EXPECT_EQ(_data.size(), leaf.numBytes());
|
|
||||||
EXPECT_EQ(0, std::memcmp(_data.data(), leaf.data(), _data.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
DataBlockFixture _data;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TwoLevelDataFixture {
|
|
||||||
public:
|
|
||||||
TwoLevelDataFixture(DataNodeStore *dataNodeStore): _dataNodeStore(dataNodeStore) {}
|
|
||||||
|
|
||||||
void FillInto(DataInnerNode *node) {
|
|
||||||
for (int i = 0; i < node->numChildren(); ++i) {
|
|
||||||
auto leafnode = _dataNodeStore->load(node->getChild(i)->key());
|
|
||||||
auto leaf = dynamic_pointer_move<DataLeafNode>(leafnode);
|
|
||||||
LeafDataFixture(size(i), i).FillInto(leaf.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EXPECT_DATA_CORRECT(const DataInnerNode &node) const {
|
|
||||||
for (int i = 0; i < node.numChildren(); ++i) {
|
|
||||||
auto leafnode =_dataNodeStore->load(node.getChild(i)->key());
|
|
||||||
auto leaf = dynamic_pointer_move<DataLeafNode>(leafnode);
|
|
||||||
LeafDataFixture(size(i), i).EXPECT_DATA_CORRECT(*leaf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
DataNodeStore *_dataNodeStore;
|
|
||||||
|
|
||||||
static int size(int childIndex) {
|
|
||||||
return DataLeafNode::MAX_STORED_BYTES-childIndex;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class DataTreeGrowingDataTest: public DataTreeGrowingTest {
|
|
||||||
public:
|
|
||||||
unique_ptr<DataTree> CreateLeafOnlyTreeWithData(const LeafDataFixture &data) {
|
|
||||||
auto leafnode = nodeStore.createNewLeafNode();
|
|
||||||
data.FillInto(leafnode.get());
|
|
||||||
|
|
||||||
return make_unique<DataTree>(&nodeStore, std::move(leafnode));
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataTree> CreateTwoNodeTreeWithData(const LeafDataFixture &data) {
|
|
||||||
auto tree = CreateLeafOnlyTreeWithData(data);
|
|
||||||
tree->addDataLeaf();
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataTree> CreateThreeNodeChainedTreeWithData(const LeafDataFixture &data) {
|
|
||||||
auto leaf = nodeStore.createNewLeafNode();
|
|
||||||
data.FillInto(leaf.get());
|
|
||||||
|
|
||||||
auto inner = nodeStore.createNewInnerNode(*leaf);
|
|
||||||
return make_unique<DataTree>(&nodeStore, nodeStore.createNewInnerNode(*inner));
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataTree> CreateFullTwoLevelTreeWithData(TwoLevelDataFixture *data) {
|
|
||||||
auto root = LoadInnerNode(CreateFullTwoLevelTree());
|
|
||||||
assert(root->numChildren() == DataInnerNode::MAX_STORED_CHILDREN);
|
|
||||||
data->FillInto(root.get());
|
|
||||||
return make_unique<DataTree>(&nodeStore, std::move(root));
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataTree> CreateThreeLevelTreeWithLowerLevelFullWithData(TwoLevelDataFixture *data) {
|
|
||||||
auto _node = LoadFirstChildOf(CreateThreeLevelTreeWithLowerLevelFullReturnRootKey());
|
|
||||||
auto node = dynamic_pointer_move<DataInnerNode>(_node);
|
|
||||||
data->FillInto(node.get());
|
|
||||||
return make_unique<DataTree>(&nodeStore, std::move(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataNode> LoadFirstChildOf(const Key &key) {
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
return nodeStore.load(root->getChild(0)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataLeafNode> LoadFirstLeafOf(const Key &key) {
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
return LoadLeafNode(root->getChild(0)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataLeafNode> LoadTwoLevelFirstLeafOf(const Key &key) {
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
auto inner = LoadInnerNode(root->getChild(0)->key());
|
|
||||||
return LoadLeafNode(inner->getChild(0)->key());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingDataTest, GrowAFullTwoLevelTree_DataStaysIntact) {
|
|
||||||
TwoLevelDataFixture data(&nodeStore);
|
|
||||||
auto tree = CreateFullTwoLevelTreeWithData(&data);
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->flush();
|
|
||||||
|
|
||||||
auto node = LoadFirstChildOf(tree->key());
|
|
||||||
data.EXPECT_DATA_CORRECT(*dynamic_pointer_move<DataInnerNode>(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeGrowingDataTest, GrowAThreeLevelTreeWithLowerLevelFull_DataStaysIntact) {
|
|
||||||
TwoLevelDataFixture data(&nodeStore);
|
|
||||||
auto tree = CreateThreeLevelTreeWithLowerLevelFullWithData(&data);
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->flush();
|
|
||||||
|
|
||||||
auto node = LoadFirstChildOf(tree->key());
|
|
||||||
data.EXPECT_DATA_CORRECT(*dynamic_pointer_move<DataInnerNode>(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
class DataTreeGrowingDataTest_OneDataLeaf: public DataTreeGrowingDataTest, public WithParamInterface<uint32_t> {
|
|
||||||
};
|
|
||||||
INSTANTIATE_TEST_CASE_P(DataTreeGrowingDataTest_OneDataLeaf, DataTreeGrowingDataTest_OneDataLeaf, Values(0, 1, DataLeafNode::MAX_STORED_BYTES-2, DataLeafNode::MAX_STORED_BYTES-1, DataLeafNode::MAX_STORED_BYTES));
|
|
||||||
|
|
||||||
TEST_P(DataTreeGrowingDataTest_OneDataLeaf, GrowAOneNodeTree_DataStaysIntact) {
|
|
||||||
LeafDataFixture data(GetParam());
|
|
||||||
auto tree = CreateLeafOnlyTreeWithData(data);
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->flush();
|
|
||||||
|
|
||||||
auto leaf = LoadFirstLeafOf(tree->key());
|
|
||||||
data.EXPECT_DATA_CORRECT(*leaf);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_P(DataTreeGrowingDataTest_OneDataLeaf, GrowATwoNodeTree_DataStaysIntact) {
|
|
||||||
LeafDataFixture data(GetParam());
|
|
||||||
auto tree = CreateTwoNodeTreeWithData(data);
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->flush();
|
|
||||||
|
|
||||||
auto leaf = LoadFirstLeafOf(tree->key());
|
|
||||||
data.EXPECT_DATA_CORRECT(*leaf);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_P(DataTreeGrowingDataTest_OneDataLeaf, GrowAThreeNodeChainedTree_DataStaysIntact) {
|
|
||||||
LeafDataFixture data(GetParam());
|
|
||||||
auto tree = CreateThreeNodeChainedTreeWithData(data);
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->flush();
|
|
||||||
|
|
||||||
auto leaf = LoadTwoLevelFirstLeafOf(tree->key());
|
|
||||||
data.EXPECT_DATA_CORRECT(*leaf);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Test tree depth markers on the nodes
|
|
||||||
//TODO Build-up test cases (build a leaf tree, add N leaves and check end state. End states for example FullTwoLevelTree, FullThreeLevelTree)
|
|
@ -1,70 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef TEST_BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_DATATREETEST_H_
|
|
||||||
#define TEST_BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_DATATREETEST_H_
|
|
||||||
|
|
||||||
#include "google/gtest/gtest.h"
|
|
||||||
|
|
||||||
#include "../../../../implementations/onblocks/datanodestore/DataNodeStore.h"
|
|
||||||
#include "../../../../implementations/onblocks/datanodestore/DataInnerNode.h"
|
|
||||||
#include "../../../../implementations/onblocks/datanodestore/DataLeafNode.h"
|
|
||||||
#include "../../../../implementations/onblocks/datatreestore/DataTree.h"
|
|
||||||
#include "messmer/blockstore/implementations/testfake/FakeBlockStore.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using blobstore::onblocks::datanodestore::DataNodeStore;
|
|
||||||
using blobstore::onblocks::datanodestore::DataInnerNode;
|
|
||||||
using blobstore::onblocks::datatreestore::DataTree;
|
|
||||||
using blockstore::testfake::FakeBlockStore;
|
|
||||||
using blockstore::Key;
|
|
||||||
using std::make_unique;
|
|
||||||
using std::unique_ptr;
|
|
||||||
|
|
||||||
class DataTreeTest: public ::testing::Test {
|
|
||||||
public:
|
|
||||||
DataTreeTest():
|
|
||||||
nodeStore(make_unique<FakeBlockStore>()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataTree> CreateLeafOnlyTree() {
|
|
||||||
auto leafnode = nodeStore.createNewLeafNode();
|
|
||||||
return make_unique<DataTree>(&nodeStore, std::move(leafnode));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FillNode(DataInnerNode *node) {
|
|
||||||
for(unsigned int i=node->numChildren(); i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
|
|
||||||
node->addChild(*nodeStore.createNewLeafNode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FillNodeTwoLevel(DataInnerNode *node) {
|
|
||||||
for(unsigned int i=node->numChildren(); i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
|
|
||||||
auto inner_node = nodeStore.createNewInnerNode(*nodeStore.createNewLeafNode());
|
|
||||||
for(unsigned int j = 1;j < DataInnerNode::MAX_STORED_CHILDREN; ++j) {
|
|
||||||
inner_node->addChild(*nodeStore.createNewLeafNode());
|
|
||||||
}
|
|
||||||
node->addChild(*inner_node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Key CreateFullTwoLevelTree() {
|
|
||||||
auto leaf = nodeStore.createNewLeafNode();
|
|
||||||
auto root = nodeStore.createNewInnerNode(*leaf);
|
|
||||||
FillNode(root.get());
|
|
||||||
return root->key();
|
|
||||||
}
|
|
||||||
|
|
||||||
Key CreateFullThreeLevelTree() {
|
|
||||||
auto leaf = nodeStore.createNewLeafNode();
|
|
||||||
auto node = nodeStore.createNewInnerNode(*leaf);
|
|
||||||
auto root = nodeStore.createNewInnerNode(*node);
|
|
||||||
FillNode(node.get());
|
|
||||||
FillNodeTwoLevel(root.get());
|
|
||||||
return root->key();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataNodeStore nodeStore;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||||||
|
#include "testutils/DataTreeGrowingTest.h"
|
||||||
|
|
||||||
|
#include "../../../../testutils/DataBlockFixture.h"
|
||||||
|
|
||||||
|
using ::testing::WithParamInterface;
|
||||||
|
using ::testing::Values;
|
||||||
|
|
||||||
|
using std::unique_ptr;
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
|
using cpputils::dynamic_pointer_move;
|
||||||
|
using namespace blobstore::onblocks::datatreestore;
|
||||||
|
|
||||||
|
using blobstore::onblocks::datanodestore::DataNode;
|
||||||
|
using blobstore::onblocks::datanodestore::DataNodeStore;
|
||||||
|
using blobstore::onblocks::datanodestore::DataInnerNode;
|
||||||
|
using blobstore::onblocks::datanodestore::DataLeafNode;
|
||||||
|
using blockstore::Key;
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest, GrowAOneNodeTree_FlushingWorks) {
|
||||||
|
//Tests that after calling flush(), the complete grown tree structure is written to the blockstore
|
||||||
|
auto tree = CreateLeafOnlyTree();
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->flush();
|
||||||
|
|
||||||
|
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(2, tree->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO Test tree depth markers on the nodes
|
||||||
|
//TODO Build-up test cases (build a leaf tree, add N leaves and check end state. End states for example FullTwoLevelTree, FullThreeLevelTree)
|
@ -0,0 +1,123 @@
|
|||||||
|
#include "testutils/DataTreeGrowingTest.h"
|
||||||
|
#include "testutils/LeafDataFixture.h"
|
||||||
|
#include "testutils/TwoLevelDataFixture.h"
|
||||||
|
|
||||||
|
using std::unique_ptr;
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
|
using ::testing::WithParamInterface;
|
||||||
|
using ::testing::Values;
|
||||||
|
|
||||||
|
using namespace blobstore::onblocks::datanodestore;
|
||||||
|
using namespace blobstore::onblocks::datatreestore;
|
||||||
|
|
||||||
|
using blockstore::Key;
|
||||||
|
using cpputils::dynamic_pointer_move;
|
||||||
|
|
||||||
|
class DataTreeGrowingTest_DataStaysIntact: public DataTreeGrowingTest {
|
||||||
|
public:
|
||||||
|
unique_ptr<DataTree> CreateLeafOnlyTreeWithData(const LeafDataFixture &data) {
|
||||||
|
auto leafnode = nodeStore.createNewLeafNode();
|
||||||
|
data.FillInto(leafnode.get());
|
||||||
|
|
||||||
|
return make_unique<DataTree>(&nodeStore, std::move(leafnode));
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataTree> CreateTwoNodeTreeWithData(const LeafDataFixture &data) {
|
||||||
|
auto tree = CreateLeafOnlyTreeWithData(data);
|
||||||
|
tree->addDataLeaf();
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataTree> CreateThreeNodeChainedTreeWithData(const LeafDataFixture &data) {
|
||||||
|
auto leaf = nodeStore.createNewLeafNode();
|
||||||
|
data.FillInto(leaf.get());
|
||||||
|
|
||||||
|
auto inner = nodeStore.createNewInnerNode(*leaf);
|
||||||
|
return make_unique<DataTree>(&nodeStore, nodeStore.createNewInnerNode(*inner));
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataTree> CreateFullTwoLevelTreeWithData(TwoLevelDataFixture *data) {
|
||||||
|
auto root = LoadInnerNode(CreateFullTwoLevelTree());
|
||||||
|
assert(root->numChildren() == DataInnerNode::MAX_STORED_CHILDREN);
|
||||||
|
data->FillInto(root.get());
|
||||||
|
return make_unique<DataTree>(&nodeStore, std::move(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataTree> CreateThreeLevelTreeWithLowerLevelFullWithData(TwoLevelDataFixture *data) {
|
||||||
|
auto _node = LoadFirstChildOf(CreateThreeLevelTreeWithLowerLevelFullReturnRootKey());
|
||||||
|
auto node = dynamic_pointer_move<DataInnerNode>(_node);
|
||||||
|
data->FillInto(node.get());
|
||||||
|
return make_unique<DataTree>(&nodeStore, std::move(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataNode> LoadFirstChildOf(const Key &key) {
|
||||||
|
auto root = LoadInnerNode(key);
|
||||||
|
return nodeStore.load(root->getChild(0)->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataLeafNode> LoadFirstLeafOf(const Key &key) {
|
||||||
|
auto root = LoadInnerNode(key);
|
||||||
|
return LoadLeafNode(root->getChild(0)->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataLeafNode> LoadTwoLevelFirstLeafOf(const Key &key) {
|
||||||
|
auto root = LoadInnerNode(key);
|
||||||
|
auto inner = LoadInnerNode(root->getChild(0)->key());
|
||||||
|
return LoadLeafNode(inner->getChild(0)->key());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_DataStaysIntact, GrowAFullTwoLevelTree) {
|
||||||
|
TwoLevelDataFixture data(&nodeStore);
|
||||||
|
auto tree = CreateFullTwoLevelTreeWithData(&data);
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->flush();
|
||||||
|
|
||||||
|
auto node = LoadFirstChildOf(tree->key());
|
||||||
|
data.EXPECT_DATA_CORRECT(*dynamic_pointer_move<DataInnerNode>(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_DataStaysIntact, GrowAThreeLevelTreeWithLowerLevelFull) {
|
||||||
|
TwoLevelDataFixture data(&nodeStore);
|
||||||
|
auto tree = CreateThreeLevelTreeWithLowerLevelFullWithData(&data);
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->flush();
|
||||||
|
|
||||||
|
auto node = LoadFirstChildOf(tree->key());
|
||||||
|
data.EXPECT_DATA_CORRECT(*dynamic_pointer_move<DataInnerNode>(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataTreeGrowingTest_DataStaysIntact_OneDataLeaf: public DataTreeGrowingTest_DataStaysIntact, public WithParamInterface<uint32_t> {
|
||||||
|
};
|
||||||
|
INSTANTIATE_TEST_CASE_P(DataTreeGrowingTest_DataStaysIntact_OneDataLeaf, DataTreeGrowingTest_DataStaysIntact_OneDataLeaf, Values(0, 1, DataLeafNode::MAX_STORED_BYTES-2, DataLeafNode::MAX_STORED_BYTES-1, DataLeafNode::MAX_STORED_BYTES));
|
||||||
|
|
||||||
|
TEST_P(DataTreeGrowingTest_DataStaysIntact_OneDataLeaf, GrowAOneNodeTree) {
|
||||||
|
LeafDataFixture data(GetParam());
|
||||||
|
auto tree = CreateLeafOnlyTreeWithData(data);
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->flush();
|
||||||
|
|
||||||
|
auto leaf = LoadFirstLeafOf(tree->key());
|
||||||
|
data.EXPECT_DATA_CORRECT(*leaf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(DataTreeGrowingTest_DataStaysIntact_OneDataLeaf, GrowATwoNodeTree) {
|
||||||
|
LeafDataFixture data(GetParam());
|
||||||
|
auto tree = CreateTwoNodeTreeWithData(data);
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->flush();
|
||||||
|
|
||||||
|
auto leaf = LoadFirstLeafOf(tree->key());
|
||||||
|
data.EXPECT_DATA_CORRECT(*leaf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(DataTreeGrowingTest_DataStaysIntact_OneDataLeaf, GrowAThreeNodeChainedTree) {
|
||||||
|
LeafDataFixture data(GetParam());
|
||||||
|
auto tree = CreateThreeNodeChainedTreeWithData(data);
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->flush();
|
||||||
|
|
||||||
|
auto leaf = LoadTwoLevelFirstLeafOf(tree->key());
|
||||||
|
data.EXPECT_DATA_CORRECT(*leaf);
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
#include "testutils/DataTreeGrowingTest.h"
|
||||||
|
|
||||||
|
class DataTreeGrowingTest_KeyDoesntChange: public DataTreeGrowingTest {};
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowAOneNodeTree) {
|
||||||
|
auto key = CreateLeafOnlyTree()->key();
|
||||||
|
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowATwoNodeTree) {
|
||||||
|
auto key = CreateTreeAddOneLeafReturnRootKey();
|
||||||
|
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowATwoLevelThreeNodeTree) {
|
||||||
|
auto key = CreateTreeAddTwoLeavesReturnRootKey();
|
||||||
|
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowAThreeNodeChainedTree) {
|
||||||
|
auto root_key = CreateThreeNodeChainedTreeReturnRootKey();
|
||||||
|
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowAThreeLevelTreeWithLowerLevelFull) {
|
||||||
|
auto root_key = CreateThreeLevelTreeWithLowerLevelFullReturnRootKey();
|
||||||
|
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowAFullTwoLevelTree) {
|
||||||
|
auto root_key = CreateFullTwoLevelTree();
|
||||||
|
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowAFullThreeLevelTree) {
|
||||||
|
auto root_key = CreateFullThreeLevelTree();
|
||||||
|
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_KeyDoesntChange, GrowAThreeLevelTreeWithTwoFullSubtrees) {
|
||||||
|
auto root_key = CreateThreeLevelTreeWithTwoFullSubtrees();
|
||||||
|
EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(root_key);
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
#include "testutils/DataTreeGrowingTest.h"
|
||||||
|
|
||||||
|
class DataTreeGrowingTest_Structure: public DataTreeGrowingTest {};
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_Structure, GrowAOneNodeTree) {
|
||||||
|
auto key = CreateTreeAddOneLeafReturnRootKey();
|
||||||
|
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(2, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_Structure, GrowATwoNodeTree) {
|
||||||
|
auto key = CreateTreeAddTwoLeavesReturnRootKey();
|
||||||
|
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(3, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_Structure, GrowATwoLevelThreeNodeTree) {
|
||||||
|
auto key = CreateTreeAddThreeLeavesReturnRootKey();
|
||||||
|
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(4, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_Structure, GrowAThreeNodeChainedTree) {
|
||||||
|
auto key = CreateThreeNodeChainedTreeReturnRootKey();
|
||||||
|
AddLeafTo(key);
|
||||||
|
|
||||||
|
auto root = LoadInnerNode(key);
|
||||||
|
EXPECT_EQ(1u, root->numChildren());
|
||||||
|
|
||||||
|
EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(2, root->getChild(0)->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_Structure, GrowAFullTwoLevelTree) {
|
||||||
|
auto root_key = CreateFullTwoLevelTree();
|
||||||
|
AddLeafTo(root_key);
|
||||||
|
|
||||||
|
auto root = LoadInnerNode(root_key);
|
||||||
|
EXPECT_EQ(2u, root->numChildren());
|
||||||
|
|
||||||
|
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(0)->key());
|
||||||
|
EXPECT_IS_TWONODE_CHAIN(root->getChild(1)->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_Structure, GrowAThreeLevelTreeWithLowerLevelFull) {
|
||||||
|
auto root_key = CreateThreeLevelTreeWithLowerLevelFullReturnRootKey();
|
||||||
|
AddLeafTo(root_key);
|
||||||
|
|
||||||
|
auto root = LoadInnerNode(root_key);
|
||||||
|
EXPECT_EQ(2u, root->numChildren());
|
||||||
|
|
||||||
|
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(0)->key());
|
||||||
|
EXPECT_IS_TWONODE_CHAIN(root->getChild(1)->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_Structure, GrowAFullThreeLevelTree) {
|
||||||
|
auto root_key = CreateFullThreeLevelTree();
|
||||||
|
AddLeafTo(root_key);
|
||||||
|
|
||||||
|
auto root = LoadInnerNode(root_key);
|
||||||
|
EXPECT_EQ(2u, root->numChildren());
|
||||||
|
|
||||||
|
EXPECT_IS_FULL_THREELEVEL_TREE(root->getChild(0)->key());
|
||||||
|
EXPECT_IS_THREENODE_CHAIN(root->getChild(1)->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DataTreeGrowingTest_Structure, GrowAThreeLevelTreeWithTwoFullSubtrees) {
|
||||||
|
auto root_key = CreateThreeLevelTreeWithTwoFullSubtrees();
|
||||||
|
AddLeafTo(root_key);
|
||||||
|
|
||||||
|
auto root = LoadInnerNode(root_key);
|
||||||
|
EXPECT_EQ(3u, root->numChildren());
|
||||||
|
|
||||||
|
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(0)->key());
|
||||||
|
EXPECT_IS_FULL_TWOLEVEL_TREE(root->getChild(1)->key());
|
||||||
|
EXPECT_IS_TWONODE_CHAIN(root->getChild(2)->key());
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
#include "DataTreeGrowingTest.h"
|
||||||
|
|
||||||
|
using namespace blobstore::onblocks::datanodestore;
|
||||||
|
|
||||||
|
using std::unique_ptr;
|
||||||
|
using cpputils::dynamic_pointer_move;
|
||||||
|
using blockstore::Key;
|
||||||
|
using blobstore::onblocks::datatreestore::DataTree;
|
||||||
|
|
||||||
|
Key DataTreeGrowingTest::CreateTreeAddOneLeafReturnRootKey() {
|
||||||
|
auto tree = CreateLeafOnlyTree();
|
||||||
|
auto key = tree->key();
|
||||||
|
tree->addDataLeaf();
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key DataTreeGrowingTest::CreateTreeAddTwoLeavesReturnRootKey() {
|
||||||
|
auto tree = CreateLeafOnlyTree();
|
||||||
|
auto key = tree->key();
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->addDataLeaf();
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key DataTreeGrowingTest::CreateTreeAddThreeLeavesReturnRootKey() {
|
||||||
|
auto tree = CreateLeafOnlyTree();
|
||||||
|
auto key = tree->key();
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->addDataLeaf();
|
||||||
|
tree->addDataLeaf();
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key DataTreeGrowingTest::CreateThreeNodeChainedTreeReturnRootKey() {
|
||||||
|
auto leaf = nodeStore.createNewLeafNode();
|
||||||
|
auto node = nodeStore.createNewInnerNode(*leaf);
|
||||||
|
auto root = nodeStore.createNewInnerNode(*node);
|
||||||
|
return root->key();
|
||||||
|
}
|
||||||
|
|
||||||
|
Key DataTreeGrowingTest::CreateThreeLevelTreeWithLowerLevelFullReturnRootKey() {
|
||||||
|
auto leaf = nodeStore.createNewLeafNode();
|
||||||
|
auto node = nodeStore.createNewInnerNode(*leaf);
|
||||||
|
FillNode(node.get());
|
||||||
|
auto root = nodeStore.createNewInnerNode(*node);
|
||||||
|
return root->key();
|
||||||
|
}
|
||||||
|
|
||||||
|
Key DataTreeGrowingTest::CreateThreeLevelTreeWithTwoFullSubtrees() {
|
||||||
|
auto leaf1 = nodeStore.createNewLeafNode();
|
||||||
|
auto leaf2 = nodeStore.createNewLeafNode();
|
||||||
|
auto leaf3 = nodeStore.createNewLeafNode();
|
||||||
|
auto node1 = nodeStore.createNewInnerNode(*leaf1);
|
||||||
|
FillNode(node1.get());
|
||||||
|
auto node2 = nodeStore.createNewInnerNode(*leaf2);
|
||||||
|
FillNode(node2.get());
|
||||||
|
auto root = nodeStore.createNewInnerNode(*node1);
|
||||||
|
root->addChild(*node2);
|
||||||
|
return root->key();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::AddLeafTo(const Key &key) {
|
||||||
|
DataTree tree(&nodeStore, nodeStore.load(key));
|
||||||
|
tree.addDataLeaf();
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataInnerNode> DataTreeGrowingTest::LoadInnerNode(const Key &key) {
|
||||||
|
auto node = nodeStore.load(key);
|
||||||
|
auto casted = dynamic_pointer_move<DataInnerNode>(node);
|
||||||
|
EXPECT_NE(nullptr, casted.get()) << "Is not an inner node";
|
||||||
|
return casted;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataLeafNode> DataTreeGrowingTest::DataTreeGrowingTest::LoadLeafNode(const Key &key) {
|
||||||
|
auto node = nodeStore.load(key);
|
||||||
|
auto casted = dynamic_pointer_move<DataLeafNode>(node);
|
||||||
|
EXPECT_NE(nullptr, casted.get()) << "Is not a leaf node";
|
||||||
|
return casted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::EXPECT_IS_LEAF_NODE(const Key &key) {
|
||||||
|
auto node = LoadLeafNode(key);
|
||||||
|
EXPECT_NE(nullptr, node.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::EXPECT_IS_INNER_NODE(const Key &key) {
|
||||||
|
auto node = LoadInnerNode(key);
|
||||||
|
EXPECT_NE(nullptr, node.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::EXPECT_IS_FULL_TWOLEVEL_TREE(const Key &key) {
|
||||||
|
auto node = LoadInnerNode(key);
|
||||||
|
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
|
||||||
|
for (unsigned int i = 0; i < node->numChildren(); ++i) {
|
||||||
|
EXPECT_IS_LEAF_NODE(node->getChild(i)->key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::EXPECT_IS_FULL_THREELEVEL_TREE(const Key &key) {
|
||||||
|
auto root = LoadInnerNode(key);
|
||||||
|
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, root->numChildren());
|
||||||
|
for (unsigned int i = 0; i < root->numChildren(); ++i) {
|
||||||
|
auto node = LoadInnerNode(root->getChild(i)->key());
|
||||||
|
EXPECT_EQ(DataInnerNode::MAX_STORED_CHILDREN, node->numChildren());
|
||||||
|
for (unsigned int j = 0; j < node->numChildren(); ++j) {
|
||||||
|
EXPECT_IS_LEAF_NODE(node->getChild(j)->key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::EXPECT_IS_TWONODE_CHAIN(const Key &key) {
|
||||||
|
auto node = LoadInnerNode(key);
|
||||||
|
EXPECT_EQ(1u, node->numChildren());
|
||||||
|
EXPECT_IS_LEAF_NODE(node->getChild(0)->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::EXPECT_IS_THREENODE_CHAIN(const Key &key) {
|
||||||
|
auto node1 = LoadInnerNode(key);
|
||||||
|
EXPECT_EQ(1u, node1->numChildren());
|
||||||
|
auto node2 = LoadInnerNode(node1->getChild(0)->key());
|
||||||
|
EXPECT_EQ(1u, node2->numChildren());
|
||||||
|
EXPECT_IS_LEAF_NODE(node2->getChild(0)->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(const Key &key) {
|
||||||
|
DataTree tree(&nodeStore, nodeStore.load(key));
|
||||||
|
tree.addDataLeaf();
|
||||||
|
EXPECT_EQ(key, tree.key());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeGrowingTest::EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(unsigned int expectedNumberOfLeaves, const Key &key) {
|
||||||
|
auto node = LoadInnerNode(key);
|
||||||
|
EXPECT_EQ(expectedNumberOfLeaves, node->numChildren());
|
||||||
|
for(unsigned int i=0;i<expectedNumberOfLeaves;++i) {
|
||||||
|
EXPECT_IS_LEAF_NODE(node->getChild(i)->key());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_DATATREEGROWINGTEST_H_
|
||||||
|
#define BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_DATATREEGROWINGTEST_H_
|
||||||
|
|
||||||
|
#include "../../testutils/DataTreeTest.h"
|
||||||
|
|
||||||
|
#include "../../../../../../implementations/onblocks/datanodestore/DataLeafNode.h"
|
||||||
|
#include "../../../../../../implementations/onblocks/datanodestore/DataInnerNode.h"
|
||||||
|
|
||||||
|
#include "messmer/cpp-utils/pointer.h"
|
||||||
|
|
||||||
|
class DataTreeGrowingTest: public DataTreeTest {
|
||||||
|
public:
|
||||||
|
|
||||||
|
blockstore::Key CreateTreeAddOneLeafReturnRootKey();
|
||||||
|
blockstore::Key CreateTreeAddTwoLeavesReturnRootKey();
|
||||||
|
blockstore::Key CreateTreeAddThreeLeavesReturnRootKey();
|
||||||
|
blockstore::Key CreateThreeNodeChainedTreeReturnRootKey();
|
||||||
|
blockstore::Key CreateThreeLevelTreeWithLowerLevelFullReturnRootKey();
|
||||||
|
blockstore::Key CreateThreeLevelTreeWithTwoFullSubtrees();
|
||||||
|
void AddLeafTo(const blockstore::Key &key);
|
||||||
|
std::unique_ptr<blobstore::onblocks::datanodestore::DataInnerNode> LoadInnerNode(const blockstore::Key &key);
|
||||||
|
std::unique_ptr<blobstore::onblocks::datanodestore::DataLeafNode> LoadLeafNode(const blockstore::Key &key);
|
||||||
|
|
||||||
|
void EXPECT_IS_LEAF_NODE(const blockstore::Key &key);
|
||||||
|
void EXPECT_IS_INNER_NODE(const blockstore::Key &key);
|
||||||
|
void EXPECT_IS_FULL_TWOLEVEL_TREE(const blockstore::Key &key);
|
||||||
|
void EXPECT_IS_FULL_THREELEVEL_TREE(const blockstore::Key &key);
|
||||||
|
void EXPECT_IS_TWONODE_CHAIN(const blockstore::Key &key);
|
||||||
|
void EXPECT_IS_THREENODE_CHAIN(const blockstore::Key &key);
|
||||||
|
void EXPECT_KEY_DOESNT_CHANGE_WHEN_GROWING(const blockstore::Key &key);
|
||||||
|
void EXPECT_INNER_NODE_NUMBER_OF_LEAVES_IS(unsigned int expectedNumberOfLeaves, const blockstore::Key &key);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_LEAFDATAFIXTURE_H_
|
||||||
|
#define BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_LEAFDATAFIXTURE_H_
|
||||||
|
|
||||||
|
#include <google/gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "../../../../../testutils/DataBlockFixture.h"
|
||||||
|
|
||||||
|
// A data fixture containing data for a leaf.
|
||||||
|
// The class can fill this data into a given leaf
|
||||||
|
// and check, whether the data stored in a given leaf is correct.
|
||||||
|
class LeafDataFixture {
|
||||||
|
public:
|
||||||
|
LeafDataFixture(int size, int iv = 0): _data(size, iv) {}
|
||||||
|
|
||||||
|
void FillInto(blobstore::onblocks::datanodestore::DataLeafNode *leaf) const {
|
||||||
|
leaf->resize(_data.size());
|
||||||
|
std::memcpy(leaf->data(), _data.data(), _data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EXPECT_DATA_CORRECT(const blobstore::onblocks::datanodestore::DataLeafNode &leaf) const {
|
||||||
|
EXPECT_EQ(_data.size(), leaf.numBytes());
|
||||||
|
EXPECT_EQ(0, std::memcmp(_data.data(), leaf.data(), _data.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DataBlockFixture _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_TWOLEVELDATAFIXTURE_H_
|
||||||
|
#define BLOCKS_MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_TWOLEVELDATAFIXTURE_H_
|
||||||
|
|
||||||
|
#include <messmer/cpp-utils/macros.h>
|
||||||
|
|
||||||
|
// A data fixture containing data for a two-level tree (one inner node with leaf children).
|
||||||
|
// The class can fill this data into the leaf children of a given inner node
|
||||||
|
// and given an inner node can check, whether the data stored is correct.
|
||||||
|
class TwoLevelDataFixture {
|
||||||
|
public:
|
||||||
|
TwoLevelDataFixture(blobstore::onblocks::datanodestore::DataNodeStore *dataNodeStore): _dataNodeStore(dataNodeStore) {}
|
||||||
|
|
||||||
|
void FillInto(blobstore::onblocks::datanodestore::DataInnerNode *node) {
|
||||||
|
for (int i = 0; i < node->numChildren(); ++i) {
|
||||||
|
auto leafnode = _dataNodeStore->load(node->getChild(i)->key());
|
||||||
|
auto leaf = cpputils::dynamic_pointer_move<blobstore::onblocks::datanodestore::DataLeafNode>(leafnode);
|
||||||
|
LeafDataFixture(size(i), i).FillInto(leaf.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EXPECT_DATA_CORRECT(const blobstore::onblocks::datanodestore::DataInnerNode &node) const {
|
||||||
|
for (int i = 0; i < node.numChildren(); ++i) {
|
||||||
|
auto leafnode =_dataNodeStore->load(node.getChild(i)->key());
|
||||||
|
auto leaf = cpputils::dynamic_pointer_move<blobstore::onblocks::datanodestore::DataLeafNode>(leafnode);
|
||||||
|
LeafDataFixture(size(i), i).EXPECT_DATA_CORRECT(*leaf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
blobstore::onblocks::datanodestore::DataNodeStore *_dataNodeStore;
|
||||||
|
|
||||||
|
static int size(int childIndex) {
|
||||||
|
return blobstore::onblocks::datanodestore::DataLeafNode::MAX_STORED_BYTES-childIndex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,9 +1,10 @@
|
|||||||
#include "google/gtest/gtest.h"
|
#include "google/gtest/gtest.h"
|
||||||
|
|
||||||
#include "../DataTreeTest.h"
|
#include "../testutils/DataTreeTest.h"
|
||||||
#include "../../../../../implementations/onblocks/datatreestore/DataTree.h"
|
#include "../../../../../implementations/onblocks/datatreestore/DataTree.h"
|
||||||
#include "../../../../../implementations/onblocks/datanodestore/DataLeafNode.h"
|
#include "../../../../../implementations/onblocks/datanodestore/DataLeafNode.h"
|
||||||
#include "../../../../../implementations/onblocks/datanodestore/DataInnerNode.h"
|
#include "../../../../../implementations/onblocks/datanodestore/DataInnerNode.h"
|
||||||
|
#include "messmer/blockstore/implementations/testfake/FakeBlockStore.h"
|
||||||
|
|
||||||
using ::testing::Test;
|
using ::testing::Test;
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
#include "DataTreeTest.h"
|
||||||
|
|
||||||
|
#include "messmer/blockstore/implementations/testfake/FakeBlockStore.h"
|
||||||
|
|
||||||
|
using blobstore::onblocks::datanodestore::DataNodeStore;
|
||||||
|
using blobstore::onblocks::datanodestore::DataInnerNode;
|
||||||
|
using blobstore::onblocks::datatreestore::DataTree;
|
||||||
|
using blockstore::testfake::FakeBlockStore;
|
||||||
|
using blockstore::Key;
|
||||||
|
using std::make_unique;
|
||||||
|
using std::unique_ptr;
|
||||||
|
|
||||||
|
DataTreeTest::DataTreeTest()
|
||||||
|
:nodeStore(make_unique<FakeBlockStore>()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<DataTree> DataTreeTest::CreateLeafOnlyTree() {
|
||||||
|
auto leafnode = nodeStore.createNewLeafNode();
|
||||||
|
return make_unique<DataTree>(&nodeStore, std::move(leafnode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeTest::FillNode(DataInnerNode *node) {
|
||||||
|
for(unsigned int i=node->numChildren(); i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
|
||||||
|
node->addChild(*nodeStore.createNewLeafNode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTreeTest::FillNodeTwoLevel(DataInnerNode *node) {
|
||||||
|
for(unsigned int i=node->numChildren(); i < DataInnerNode::MAX_STORED_CHILDREN; ++i) {
|
||||||
|
auto inner_node = nodeStore.createNewInnerNode(*nodeStore.createNewLeafNode());
|
||||||
|
for(unsigned int j = 1;j < DataInnerNode::MAX_STORED_CHILDREN; ++j) {
|
||||||
|
inner_node->addChild(*nodeStore.createNewLeafNode());
|
||||||
|
}
|
||||||
|
node->addChild(*inner_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Key DataTreeTest::CreateFullTwoLevelTree() {
|
||||||
|
auto leaf = nodeStore.createNewLeafNode();
|
||||||
|
auto root = nodeStore.createNewInnerNode(*leaf);
|
||||||
|
FillNode(root.get());
|
||||||
|
return root->key();
|
||||||
|
}
|
||||||
|
|
||||||
|
Key DataTreeTest::CreateFullThreeLevelTree() {
|
||||||
|
auto leaf = nodeStore.createNewLeafNode();
|
||||||
|
auto node = nodeStore.createNewInnerNode(*leaf);
|
||||||
|
auto root = nodeStore.createNewInnerNode(*node);
|
||||||
|
FillNode(node.get());
|
||||||
|
FillNodeTwoLevel(root.get());
|
||||||
|
return root->key();
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef TEST_BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_DATATREETEST_H_
|
||||||
|
#define TEST_BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_DATATREETEST_H_
|
||||||
|
|
||||||
|
#include "google/gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "../../../../../implementations/onblocks/datanodestore/DataNodeStore.h"
|
||||||
|
#include "../../../../../implementations/onblocks/datanodestore/DataInnerNode.h"
|
||||||
|
#include "../../../../../implementations/onblocks/datanodestore/DataLeafNode.h"
|
||||||
|
#include "../../../../../implementations/onblocks/datatreestore/DataTree.h"
|
||||||
|
|
||||||
|
class DataTreeTest: public ::testing::Test {
|
||||||
|
public:
|
||||||
|
DataTreeTest();
|
||||||
|
|
||||||
|
std::unique_ptr<blobstore::onblocks::datatreestore::DataTree> CreateLeafOnlyTree();
|
||||||
|
void FillNode(blobstore::onblocks::datanodestore::DataInnerNode *node);
|
||||||
|
void FillNodeTwoLevel(blobstore::onblocks::datanodestore::DataInnerNode *node);
|
||||||
|
blockstore::Key CreateFullTwoLevelTree();
|
||||||
|
blockstore::Key CreateFullThreeLevelTree();
|
||||||
|
blobstore::onblocks::datanodestore::DataNodeStore nodeStore;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user