From a3e6f62460abc4c086a94ca32c4c0c19ca7b98a8 Mon Sep 17 00:00:00 2001 From: Mikhail Boldyrev Date: Thu, 11 Apr 2019 09:32:47 +0300 Subject: [PATCH] StorageLimitTest Signed-off-by: Mikhail Boldyrev --- .../multi_sig_transactions/CMakeLists.txt | 8 + .../storage_limit_test.cpp | 182 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 test/module/irohad/multi_sig_transactions/storage_limit_test.cpp diff --git a/test/module/irohad/multi_sig_transactions/CMakeLists.txt b/test/module/irohad/multi_sig_transactions/CMakeLists.txt index 2f466022e4..396d69ef13 100644 --- a/test/module/irohad/multi_sig_transactions/CMakeLists.txt +++ b/test/module/irohad/multi_sig_transactions/CMakeLists.txt @@ -66,3 +66,11 @@ target_link_libraries(mst_to_pcs_propagation_test shared_model_proto_backend test_logger ) + +AddTest(storage_limit_test storage_limit_test.cpp) +target_link_libraries(storage_limit_test + schema + shared_model_interfaces_factories + shared_model_proto_backend + test_logger + ) diff --git a/test/module/irohad/multi_sig_transactions/storage_limit_test.cpp b/test/module/irohad/multi_sig_transactions/storage_limit_test.cpp new file mode 100644 index 0000000000..e5954ac792 --- /dev/null +++ b/test/module/irohad/multi_sig_transactions/storage_limit_test.cpp @@ -0,0 +1,182 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "multi_sig_transactions/storage/storage_limit.hpp" + +#include +#include "module/irohad/multi_sig_transactions/mst_test_helpers.hpp" +#include "module/shared_model/interface_mocks.hpp" + +using namespace iroha; +using namespace testing; + +class StorageLimitTest : public ::testing::Test { + protected: + std::shared_ptr makeTx() { + return clone(txBuilder(tx_counter_++).build()); + } + + std::shared_ptr makeBatch( + size_t num_txs) { + shared_model::interface::types::SharedTxsCollectionType txs; + std::generate_n( + std::back_inserter(txs), num_txs, [this]() { return this->makeTx(); }); + return createMockBatchWithTransactions(txs, {}); + } + + private: + size_t tx_counter_{0}; +}; + +struct StorageImpl : public LimitableStorage { + bool insert(BatchPtr batch) override { + batches.emplace_back(std::move(batch)); + return true; + } + + std::vector batches; +}; + +template +std::vector>> generateStorages( + std::shared_ptr limit, size_t num_storages) { + std::vector>> storages; + storages.reserve(num_storages); + for (size_t i = 0; i < num_storages; ++i) { + storages.emplace_back(std::make_shared>( + limit, std::make_unique())); + } + return storages; +} + +/** + * @given 5 storages with shared limit of 10 transactions + * @when first a batch with 2 transactionsa batch with 2 transactions is + * inserted to each storage, than a batch with single transactions is tried to + * be inserted to each storage + * @then first series of batches is inserted successfully and second is not + */ +TEST_F(StorageLimitTest, SharedLimitByTxs) { + auto storages = generateStorages(std::make_shared(10), 5); + + for (auto &storage : storages) { + EXPECT_EQ(storage->batchesQuantity(), 0); + EXPECT_EQ(storage->transactionsQuantity(), 0); + EXPECT_TRUE(storage->insert(makeBatch(2))); + EXPECT_EQ(storage->batchesQuantity(), 1); + EXPECT_EQ(storage->transactionsQuantity(), 2); + } + + for (auto &storage : storages) { + EXPECT_FALSE(storage->insert(makeBatch(1))); + EXPECT_EQ(storage->batchesQuantity(), 1); + EXPECT_EQ(storage->transactionsQuantity(), 2); + } +} + +/** + * @given a storage with shared limit of 10 transactions + * @when another storage is created using its limit and is filled with 10 + * transactions, then transactions are tried to be inserted to the first storage + * @then batches are not inserted to the first storage because it would violate + * the shared limit + */ +TEST_F(StorageLimitTest, SharedLimitAddStorage) { + LimitedStorage storage1{std::make_shared(10), + std::make_unique()}; + LimitedStorage storage2{storage1.sharedLimit(), + std::make_unique()}; + EXPECT_TRUE(storage2.insert(makeBatch(10))); + EXPECT_FALSE(storage1.insert(makeBatch(1))); +} + +/** + * @given 2 storages with shared limit of 10 transactions filled to limit + * @when a batch with 3 transactions is removed from the first one + * @then the second can accept batches with up to 3 transactions in total + */ +TEST_F(StorageLimitTest, SharedLimitRemoveAndAdd) { + auto storages = generateStorages(std::make_shared(10), 2); + EXPECT_TRUE(storages[0]->insert(makeBatch(3))); + EXPECT_TRUE(storages[0]->insert(makeBatch(3))); + EXPECT_TRUE(storages[1]->insert(makeBatch(4))); + + storages[0]->extract([](auto &storage) { + auto extracted_batch = std::move(*storage.batches.begin()); + storage.batches.erase(storage.batches.begin()); + return std::vector{extracted_batch}; + }); + EXPECT_EQ(storages[0]->batchesQuantity(), 1); + EXPECT_EQ(storages[0]->transactionsQuantity(), 3); + + EXPECT_TRUE(storages[1]->insert(makeBatch(1))); + EXPECT_TRUE(storages[1]->insert(makeBatch(2))); + EXPECT_FALSE(storages[1]->insert(makeBatch(1))); +} + +/** + * @given 2 storages with shared limit of 10 transactions filled to limit + * @when a batch with 3 transactions is moved from the first one + * @then both storages do not accept any new batches + * @and the second storage can accept the moved batch + */ +TEST_F(StorageLimitTest, SharedLimitMoveBatch) { + auto storages = generateStorages(std::make_shared(10), 2); + EXPECT_TRUE(storages[0]->insert(makeBatch(3))); + EXPECT_TRUE(storages[0]->insert(makeBatch(3))); + EXPECT_TRUE(storages[1]->insert(makeBatch(4))); + + auto moved_batches = storages[0]->move([](auto &storage) { + std::vector extracted_batches; + extracted_batches.emplace_back(std::move(*storage.batches.begin())); + storage.batches.erase(storage.batches.begin()); + return extracted_batches; + }); + EXPECT_EQ(storages[0]->batchesQuantity(), 1); + EXPECT_EQ(storages[0]->transactionsQuantity(), 3); + + EXPECT_FALSE(storages[0]->insert(makeBatch(1))); + EXPECT_FALSE(storages[1]->insert(makeBatch(1))); + + ASSERT_EQ(moved_batches.size(), 1); + EXPECT_TRUE(storages[1]->insert(moved_batches.front())); + EXPECT_EQ(storages[1]->batchesQuantity(), 2); + EXPECT_EQ(storages[1]->transactionsQuantity(), 7); + + EXPECT_FALSE(storages[0]->insert(makeBatch(1))); + EXPECT_FALSE(storages[1]->insert(makeBatch(1))); +} + +/** + * @given 2 storages with shared limit of 10 transactions filled to limit + * @when a batch with 3 transactions is moved from the first one and then is + * destroyed without being inserted to any storage + * @then both storages can accept new batches with up to 3 transactions in total + */ +TEST_F(StorageLimitTest, SharedLimitMovedBatchDestroyed) { + auto storages = generateStorages(std::make_shared(10), 2); + EXPECT_TRUE(storages[0]->insert(makeBatch(3))); + EXPECT_TRUE(storages[0]->insert(makeBatch(3))); + EXPECT_TRUE(storages[1]->insert(makeBatch(4))); + + { + auto moved_batches = storages[0]->move([](auto &storage) { + std::vector extracted_batches; + extracted_batches.emplace_back(std::move(*storage.batches.begin())); + storage.batches.erase(storage.batches.begin()); + return extracted_batches; + }); + EXPECT_EQ(moved_batches.size(), 1); + + EXPECT_FALSE(storages[0]->insert(makeBatch(1))); + EXPECT_FALSE(storages[1]->insert(makeBatch(1))); + } + + EXPECT_TRUE(storages[0]->insert(makeBatch(1))); + EXPECT_TRUE(storages[1]->insert(makeBatch(2))); + + EXPECT_FALSE(storages[0]->insert(makeBatch(1))); + EXPECT_FALSE(storages[1]->insert(makeBatch(1))); +}