Implemented more tests for DataTreeTest
This commit is contained in:
parent
1b15af4a3c
commit
f115e10f6d
@ -22,5 +22,9 @@ size_t BlobOnBlocks::size() const {
|
|||||||
//return _rootnode->numBytesInThisNode();
|
//return _rootnode->numBytesInThisNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlobOnBlocks::flush() const {
|
||||||
|
_rootnode->flush();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ public:
|
|||||||
|
|
||||||
size_t size() const override;
|
size_t size() const override;
|
||||||
|
|
||||||
|
void flush() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<datanodestore::DataNode> _rootnode;
|
std::unique_ptr<datanodestore::DataNode> _rootnode;
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,8 @@ namespace blobstore {
|
|||||||
namespace onblocks {
|
namespace onblocks {
|
||||||
namespace datanodestore {
|
namespace datanodestore {
|
||||||
|
|
||||||
|
constexpr uint32_t DataInnerNode::MAX_STORED_CHILDREN;
|
||||||
|
|
||||||
DataInnerNode::DataInnerNode(DataNodeView view)
|
DataInnerNode::DataInnerNode(DataNodeView view)
|
||||||
: DataNode(std::move(view)) {
|
: DataNode(std::move(view)) {
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,10 @@ unique_ptr<DataInnerNode> DataNode::convertToNewInnerNode(unique_ptr<DataNode> n
|
|||||||
return innerNode;
|
return innerNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataNode::flush() const {
|
||||||
|
_node.flush();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ public:
|
|||||||
|
|
||||||
static std::unique_ptr<DataInnerNode> convertToNewInnerNode(std::unique_ptr<DataNode> node, const DataNode &first_child);
|
static std::unique_ptr<DataInnerNode> convertToNewInnerNode(std::unique_ptr<DataNode> node, const DataNode &first_child);
|
||||||
|
|
||||||
|
void flush() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DataNode(DataNodeView block);
|
DataNode(DataNodeView block);
|
||||||
|
|
||||||
|
@ -84,6 +84,10 @@ public:
|
|||||||
return _block->key();
|
return _block->key();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flush() const {
|
||||||
|
_block->flush();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<int offset, class Type>
|
template<int offset, class Type>
|
||||||
const Type *GetOffset() const {
|
const Type *GetOffset() const {
|
||||||
|
@ -69,6 +69,10 @@ const Key &DataTree::key() const {
|
|||||||
return _rootNode->key();
|
return _rootNode->key();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataTree::flush() const {
|
||||||
|
_rootNode->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ public:
|
|||||||
std::unique_ptr<datanodestore::DataLeafNode> addDataLeaf();
|
std::unique_ptr<datanodestore::DataLeafNode> addDataLeaf();
|
||||||
|
|
||||||
const blockstore::Key &key() const;
|
const blockstore::Key &key() const;
|
||||||
|
|
||||||
|
void flush() const;
|
||||||
private:
|
private:
|
||||||
datanodestore::DataNodeStore *_nodeStore;
|
datanodestore::DataNodeStore *_nodeStore;
|
||||||
std::unique_ptr<datanodestore::DataNode> _rootNode;
|
std::unique_ptr<datanodestore::DataNode> _rootNode;
|
||||||
|
@ -11,6 +11,8 @@ public:
|
|||||||
virtual ~Blob() {}
|
virtual ~Blob() {}
|
||||||
|
|
||||||
virtual size_t size() const = 0;
|
virtual size_t size() const = 0;
|
||||||
|
|
||||||
|
virtual void flush() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,271 @@
|
|||||||
|
#include "DataTreeTest.h"
|
||||||
|
|
||||||
|
#include "blobstore/implementations/onblocks/datatreestore/DataTree.h"
|
||||||
|
#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h"
|
||||||
|
#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h"
|
||||||
|
|
||||||
|
#include "fspp/utils/pointer.h"
|
||||||
|
|
||||||
|
using fspp::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());
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO Test that when growing, the original leaf retains its data
|
||||||
|
//TODO Test tree depth
|
@ -1,188 +0,0 @@
|
|||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
#include "blockstore/implementations/testfake/FakeBlockStore.h"
|
|
||||||
#include "blobstore/implementations/onblocks/datanodestore/DataNodeStore.h"
|
|
||||||
#include "blobstore/implementations/onblocks/datatreestore/DataTree.h"
|
|
||||||
#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h"
|
|
||||||
#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h"
|
|
||||||
|
|
||||||
#include "fspp/utils/pointer.h"
|
|
||||||
|
|
||||||
using ::testing::Test;
|
|
||||||
using std::unique_ptr;
|
|
||||||
using std::make_unique;
|
|
||||||
using fspp::dynamic_pointer_move;
|
|
||||||
|
|
||||||
using blobstore::onblocks::datanodestore::DataNodeStore;
|
|
||||||
using blobstore::onblocks::datanodestore::DataNode;
|
|
||||||
using blobstore::onblocks::datanodestore::DataInnerNode;
|
|
||||||
using blobstore::onblocks::datanodestore::DataLeafNode;
|
|
||||||
using blockstore::testfake::FakeBlockStore;
|
|
||||||
using blockstore::BlockStore;
|
|
||||||
using blockstore::Key;
|
|
||||||
|
|
||||||
namespace blobstore {
|
|
||||||
namespace onblocks {
|
|
||||||
namespace datatreestore {
|
|
||||||
|
|
||||||
class DataTreeTest: public Test {
|
|
||||||
public:
|
|
||||||
DataTreeTest():
|
|
||||||
nodeStore(make_unique<FakeBlockStore>()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataTree> CreateLeafOnlyTree() {
|
|
||||||
auto leafnode = nodeStore.createNewLeafNode();
|
|
||||||
return make_unique<DataTree>(&nodeStore, std::move(leafnode));
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
return dynamic_pointer_move<DataInnerNode>(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<DataLeafNode> LoadLeafNode(const Key &key) {
|
|
||||||
auto node = nodeStore.load(key);
|
|
||||||
return dynamic_pointer_move<DataLeafNode>(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
DataNodeStore nodeStore;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(DataTreeTest, GrowAOneNodeTree_KeyDoesntChange) {
|
|
||||||
auto tree = CreateLeafOnlyTree();
|
|
||||||
auto key = tree->key();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
EXPECT_EQ(key, tree->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeTest, GrowAOneNodeTree_Structure) {
|
|
||||||
auto key = CreateTreeAddOneLeafReturnRootKey();
|
|
||||||
|
|
||||||
EXPECT_IS_INNER_NODE(key);
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
|
|
||||||
EXPECT_EQ(2u, root->numChildren());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(0)->key());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(1)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeTest, GrowATwoNodeTree_KeyDoesntChange) {
|
|
||||||
auto tree = CreateLeafOnlyTree();
|
|
||||||
auto key = tree->key();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
EXPECT_EQ(key, tree->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeTest, GrowATwoNodeTree_Structure) {
|
|
||||||
auto key = CreateTreeAddTwoLeavesReturnRootKey();
|
|
||||||
|
|
||||||
EXPECT_IS_INNER_NODE(key);
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
|
|
||||||
EXPECT_EQ(3u, root->numChildren());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(0)->key());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(1)->key());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(2)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeTest, GrowAThreeNodeTree_KeyDoesntChange) {
|
|
||||||
auto tree = CreateLeafOnlyTree();
|
|
||||||
auto key = tree->key();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
tree->addDataLeaf();
|
|
||||||
EXPECT_EQ(key, tree->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeTest, GrowAThreeNodeTree_Structure) {
|
|
||||||
auto key = CreateTreeAddThreeLeavesReturnRootKey();
|
|
||||||
|
|
||||||
EXPECT_IS_INNER_NODE(key);
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
|
|
||||||
EXPECT_EQ(4u, root->numChildren());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(0)->key());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(1)->key());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(2)->key());
|
|
||||||
EXPECT_IS_LEAF_NODE(root->getChild(3)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeTest, GrowAThreeNodeChainedTree_KeyDoesntChange) {
|
|
||||||
auto root_key = CreateThreeNodeChainedTreeReturnRootKey();
|
|
||||||
DataTree tree(&nodeStore, nodeStore.load(root_key));
|
|
||||||
tree.addDataLeaf();
|
|
||||||
EXPECT_EQ(root_key, tree.key());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DataTreeTest, GrowAThreeNodeChainedTree_Structure) {
|
|
||||||
auto key = CreateThreeNodeChainedTreeReturnRootKey();
|
|
||||||
AddLeafTo(key);
|
|
||||||
|
|
||||||
EXPECT_IS_INNER_NODE(key);
|
|
||||||
auto root = LoadInnerNode(key);
|
|
||||||
|
|
||||||
EXPECT_EQ(1u, root->numChildren());
|
|
||||||
EXPECT_IS_INNER_NODE(root->getChild(0)->key());
|
|
||||||
auto node = LoadInnerNode(root->getChild(0)->key());
|
|
||||||
|
|
||||||
EXPECT_EQ(2u, node->numChildren());
|
|
||||||
EXPECT_IS_LEAF_NODE(node->getChild(0)->key());
|
|
||||||
EXPECT_IS_LEAF_NODE(node->getChild(1)->key());
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Grow a full two-level tree
|
|
||||||
//TODO Grow a three-level tree
|
|
||||||
//TODO Go through some cases where the right border node chosen is special
|
|
||||||
//TODO Test that when growing, the original leaf retains its data
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef TEST_BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_DATATREETEST_H_
|
||||||
|
#define TEST_BLOBSTORE_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_DATATREETEST_H_
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "blobstore/implementations/onblocks/datanodestore/DataNodeStore.h"
|
||||||
|
#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h"
|
||||||
|
#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h"
|
||||||
|
#include "blobstore/implementations/onblocks/datatreestore/DataTree.h"
|
||||||
|
#include "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
|
Loading…
Reference in New Issue
Block a user