Add unit tests for pow and storage apis

This commit is contained in:
sachaaaaa 2019-02-04 15:33:25 +11:00
parent 3a1239d973
commit 3c71c46bd3
5 changed files with 363 additions and 1 deletions

View file

@ -4,7 +4,7 @@ Storage server for Loki Service Nodes
```
mkdir build
cd build
cmake .. -DBOOST_ROOT="path to boost"
cmake ../httpserver -DBOOST_ROOT="path to boost" -DOPENSSL_ROOT_DIR="path to openssl"
cmake --build .
./httpserver 127.0.0.1 8080
```
@ -28,3 +28,12 @@ headers:
- X-Loki-recipient: "mypubkey"
- X-Loki-last-hash: "" (optional)
```
# unit tests
```
mkdir build_test
cd build_test
cmake ../unit_test -DBOOST_ROOT="path to boost" -DOPENSSL_ROOT_DIR="path to openssl"
cmake --build .
./Test --log_level=all
```

23
unit_test/CMakeLists.txt Normal file
View file

@ -0,0 +1,23 @@
cmake_minimum_required (VERSION 3.1)
add_executable (Test main.cpp storage.cpp pow.cpp)
set_property(TARGET Test PROPERTY CXX_STANDARD 11)
# library under test
add_subdirectory(../storage storage)
add_subdirectory(../pow pow)
target_link_libraries(Test PRIVATE sn_storage pow)
# boost
find_package(Boost
REQUIRED
system
filesystem
chrono
thread
unit_test_framework
)
# add_definitions (-DBOOST_TEST_DYN_LINK)
target_include_directories(Test PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(Test PRIVATE ${Boost_LIBRARIES})

2
unit_test/main.cpp Normal file
View file

@ -0,0 +1,2 @@
#define BOOST_TEST_MODULE Storage Server Tests
#include <boost/test/unit_test.hpp>

166
unit_test/pow.cpp Normal file
View file

@ -0,0 +1,166 @@
#include "pow.hpp"
#include "utils.hpp"
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(pow)
BOOST_AUTO_TEST_CASE(util_parses_a_valid_ttl) {
uint64_t ttl;
BOOST_CHECK_EQUAL(util::parseTTL("0", ttl), true);
BOOST_CHECK_EQUAL(ttl, 0);
BOOST_CHECK_EQUAL(util::parseTTL("1", ttl), true);
BOOST_CHECK_EQUAL(ttl, 1);
BOOST_CHECK_EQUAL(util::parseTTL("1000", ttl), true);
BOOST_CHECK_EQUAL(ttl, 1000);
// Maximum time to live of 4 days
BOOST_CHECK_EQUAL(util::parseTTL("345600", ttl), true);
BOOST_CHECK_EQUAL(ttl, 345600);
BOOST_CHECK_EQUAL(util::parseTTL("345601", ttl), false);
BOOST_CHECK_EQUAL(util::parseTTL("-1", ttl), false);
BOOST_CHECK_EQUAL(util::parseTTL("abcvs", ttl), false);
BOOST_CHECK_EQUAL(util::parseTTL("", ttl), false);
}
BOOST_AUTO_TEST_CASE(it_checks_a_valid_pow) {
const auto nonce = "AAAAAAABBCE=";
const auto timestamp = "1549252654";
const auto ttl = "345600";
const auto pubkey =
"05d5970e75efb8e8daccd4d07f5f59e744c3aea25cec8bfa3e43674c4a55875f4d";
const auto data =
"CAESvgMKA1BVVBIPL2FwaS92MS9tZXNzYWdlGqIDCGUSQjA1ZDU5NzBlNzVlZmI4ZThkYW"
"NjZDRkMDdmNWY1OWU3NDRjM2FlYTI1Y2VjOGJmYTNlNDM2NzRjNGE1NTg3NWY0ZDgBKNPR"
"nbWLLULQAvG1sbxpwQY7xXBBWLvYDDtHNBpHtxAMim7+"
"iSqYYfWvwrobXbUSMP55nAiIUr6iJtvM4OzQoZSV/"
"zCz5tN9T5tKAvkiVkTyAXva7Re8BO8HX3ra+zPWDsXYw12w9XA4cxY95Y/"
"6agyMjNDAhj2bhUCMiZNd8dpl5VvKxwFKdxP4zVruKRdAaJy1/xB1gCfZ/hkh2xX90n/"
"4p4SlPj/XGmjSQ73h6PWm5/"
"qb2tPNmpkb6uuPD3GpZzxxf4pyMETwhhyruJ6KLxV0eUYh5haHxgjJbs+"
"OcwjoNpGOEhDCgThcQait2Iyb4ahMWVSjt9vxrfL/7I3HbFtMT+En1J7RutRkWX6YvGHN/"
"gJApKpfGatKZAwdnUeZy+EUTuZnRzvSLOwOL6HsOFvuq4k3gQ5v5+"
"ZPfNxSO9T6JvrGzRxofo7edadxn/hqi6dkHU7koHNAjSD2AQ==";
std::string messageHash;
BOOST_CHECK_EQUAL(
checkPoW(nonce, timestamp, ttl, pubkey, data, messageHash), true);
}
BOOST_AUTO_TEST_CASE(it_checks_an_invalid_nonce) {
const auto nonce = "AAAAAAABBCD=";
const auto timestamp = "1549252654";
const auto ttl = "345600";
const auto pubkey =
"05d5970e75efb8e8daccd4d07f5f59e744c3aea25cec8bfa3e43674c4a55875f4d";
const auto data =
"CAESvgMKA1BVVBIPL2FwaS92MS9tZXNzYWdlGqIDCGUSQjA1ZDU5NzBlNzVlZmI4ZThkYW"
"NjZDRkMDdmNWY1OWU3NDRjM2FlYTI1Y2VjOGJmYTNlNDM2NzRjNGE1NTg3NWY0ZDgBKNPR"
"nbWLLULQAvG1sbxpwQY7xXBBWLvYDDtHNBpHtxAMim7+"
"iSqYYfWvwrobXbUSMP55nAiIUr6iJtvM4OzQoZSV/"
"zCz5tN9T5tKAvkiVkTyAXva7Re8BO8HX3ra+zPWDsXYw12w9XA4cxY95Y/"
"6agyMjNDAhj2bhUCMiZNd8dpl5VvKxwFKdxP4zVruKRdAaJy1/xB1gCfZ/hkh2xX90n/"
"4p4SlPj/XGmjSQ73h6PWm5/"
"qb2tPNmpkb6uuPD3GpZzxxf4pyMETwhhyruJ6KLxV0eUYh5haHxgjJbs+"
"OcwjoNpGOEhDCgThcQait2Iyb4ahMWVSjt9vxrfL/7I3HbFtMT+En1J7RutRkWX6YvGHN/"
"gJApKpfGatKZAwdnUeZy+EUTuZnRzvSLOwOL6HsOFvuq4k3gQ5v5+"
"ZPfNxSO9T6JvrGzRxofo7edadxn/hqi6dkHU7koHNAjSD2AQ==";
std::string messageHash;
BOOST_CHECK_EQUAL(
checkPoW(nonce, timestamp, ttl, pubkey, data, messageHash), false);
}
BOOST_AUTO_TEST_CASE(it_checks_an_invalid_timestamp) {
const auto nonce = "AAAAAAABBCE=";
const auto timestamp = "1549252653";
const auto ttl = "345600";
const auto pubkey =
"05d5970e75efb8e8daccd4d07f5f59e744c3aea25cec8bfa3e43674c4a55875f4d";
const auto data =
"CAESvgMKA1BVVBIPL2FwaS92MS9tZXNzYWdlGqIDCGUSQjA1ZDU5NzBlNzVlZmI4ZThkYW"
"NjZDRkMDdmNWY1OWU3NDRjM2FlYTI1Y2VjOGJmYTNlNDM2NzRjNGE1NTg3NWY0ZDgBKNPR"
"nbWLLULQAvG1sbxpwQY7xXBBWLvYDDtHNBpHtxAMim7+"
"iSqYYfWvwrobXbUSMP55nAiIUr6iJtvM4OzQoZSV/"
"zCz5tN9T5tKAvkiVkTyAXva7Re8BO8HX3ra+zPWDsXYw12w9XA4cxY95Y/"
"6agyMjNDAhj2bhUCMiZNd8dpl5VvKxwFKdxP4zVruKRdAaJy1/xB1gCfZ/hkh2xX90n/"
"4p4SlPj/XGmjSQ73h6PWm5/"
"qb2tPNmpkb6uuPD3GpZzxxf4pyMETwhhyruJ6KLxV0eUYh5haHxgjJbs+"
"OcwjoNpGOEhDCgThcQait2Iyb4ahMWVSjt9vxrfL/7I3HbFtMT+En1J7RutRkWX6YvGHN/"
"gJApKpfGatKZAwdnUeZy+EUTuZnRzvSLOwOL6HsOFvuq4k3gQ5v5+"
"ZPfNxSO9T6JvrGzRxofo7edadxn/hqi6dkHU7koHNAjSD2AQ==";
std::string messageHash;
BOOST_CHECK_EQUAL(
checkPoW(nonce, timestamp, ttl, pubkey, data, messageHash), false);
}
BOOST_AUTO_TEST_CASE(it_checks_an_invalid_ttl) {
const auto nonce = "AAAAAAABBCE=";
const auto timestamp = "1549252654";
const auto ttl = "345601";
const auto pubkey =
"05d5970e75efb8e8daccd4d07f5f59e744c3aea25cec8bfa3e43674c4a55875f4d";
const auto data =
"CAESvgMKA1BVVBIPL2FwaS92MS9tZXNzYWdlGqIDCGUSQjA1ZDU5NzBlNzVlZmI4ZThkYW"
"NjZDRkMDdmNWY1OWU3NDRjM2FlYTI1Y2VjOGJmYTNlNDM2NzRjNGE1NTg3NWY0ZDgBKNPR"
"nbWLLULQAvG1sbxpwQY7xXBBWLvYDDtHNBpHtxAMim7+"
"iSqYYfWvwrobXbUSMP55nAiIUr6iJtvM4OzQoZSV/"
"zCz5tN9T5tKAvkiVkTyAXva7Re8BO8HX3ra+zPWDsXYw12w9XA4cxY95Y/"
"6agyMjNDAhj2bhUCMiZNd8dpl5VvKxwFKdxP4zVruKRdAaJy1/xB1gCfZ/hkh2xX90n/"
"4p4SlPj/XGmjSQ73h6PWm5/"
"qb2tPNmpkb6uuPD3GpZzxxf4pyMETwhhyruJ6KLxV0eUYh5haHxgjJbs+"
"OcwjoNpGOEhDCgThcQait2Iyb4ahMWVSjt9vxrfL/7I3HbFtMT+En1J7RutRkWX6YvGHN/"
"gJApKpfGatKZAwdnUeZy+EUTuZnRzvSLOwOL6HsOFvuq4k3gQ5v5+"
"ZPfNxSO9T6JvrGzRxofo7edadxn/hqi6dkHU7koHNAjSD2AQ==";
std::string messageHash;
BOOST_CHECK_EQUAL(
checkPoW(nonce, timestamp, ttl, pubkey, data, messageHash), false);
}
BOOST_AUTO_TEST_CASE(it_checks_an_invalid_pubkey) {
const auto nonce = "AAAAAAABBCE=";
const auto timestamp = "1549252654";
const auto ttl = "345600";
const auto pubkey =
"05d5970e75efb8e8daccd4d07f5f59e744c3aea25cec8bfa3e43674c4a55875f4c";
const auto data =
"CAESvgMKA1BVVBIPL2FwaS92MS9tZXNzYWdlGqIDCGUSQjA1ZDU5NzBlNzVlZmI4ZThkYW"
"NjZDRkMDdmNWY1OWU3NDRjM2FlYTI1Y2VjOGJmYTNlNDM2NzRjNGE1NTg3NWY0ZDgBKNPR"
"nbWLLULQAvG1sbxpwQY7xXBBWLvYDDtHNBpHtxAMim7+"
"iSqYYfWvwrobXbUSMP55nAiIUr6iJtvM4OzQoZSV/"
"zCz5tN9T5tKAvkiVkTyAXva7Re8BO8HX3ra+zPWDsXYw12w9XA4cxY95Y/"
"6agyMjNDAhj2bhUCMiZNd8dpl5VvKxwFKdxP4zVruKRdAaJy1/xB1gCfZ/hkh2xX90n/"
"4p4SlPj/XGmjSQ73h6PWm5/"
"qb2tPNmpkb6uuPD3GpZzxxf4pyMETwhhyruJ6KLxV0eUYh5haHxgjJbs+"
"OcwjoNpGOEhDCgThcQait2Iyb4ahMWVSjt9vxrfL/7I3HbFtMT+En1J7RutRkWX6YvGHN/"
"gJApKpfGatKZAwdnUeZy+EUTuZnRzvSLOwOL6HsOFvuq4k3gQ5v5+"
"ZPfNxSO9T6JvrGzRxofo7edadxn/hqi6dkHU7koHNAjSD2AQ==";
std::string messageHash;
BOOST_CHECK_EQUAL(
checkPoW(nonce, timestamp, ttl, pubkey, data, messageHash), false);
}
BOOST_AUTO_TEST_CASE(it_checks_an_invalid_data) {
const auto nonce = "AAAAAAABBCE=";
const auto timestamp = "1549252654";
const auto ttl = "345600";
const auto pubkey =
"05d5970e75efb8e8daccd4d07f5f59e744c3aea25cec8bfa3e43674c4a55875f4d";
const auto data =
"CAESvgMKA1BVVBIPL2FwaS92MS9tZXNzYWdlGqIDCGUSQjA1ZDU5NzBlNzVlZmI4ZThkYW"
"NjZDRkMDdmNWY1OWU3NDRjM2FlYTI1Y2VjOGJmYTNlNDM2NzRjNGE1NTg3NWY0ZDgBKNPR"
"nbWLLULQAvG1sbxpwQY7xXBBWLvYDDtHNBpHtxAMim7+"
"iSqYYfWvwrobXbUSMP55nAiIUr6iJtvM4OzQoZSV/"
"zCz5tN9T5tKAvkiVkTyAXva7Re8BO8HX3ra+zPWDsXYw12w9XA4cxY95Y/"
"6agyMjNDAhj2bhUCMiZNd8dpl5VvKxwFKdxP4zVruKRdAaJy1/xB1gCfZ/hkh2xX90n/"
"4p4SlPj/XGmjSQ73h6PWm5/"
"qb2tPNmpkb6uuPD3GpZzxxf4pyMETwhhyruJ6KLxV0eUYh5haHxgjJbs+"
"OcwjoNpGOEhDCgThcQait2Iyb4ahMWVSjt9vxrfL/7I3HbFtMT+En1J7RutRkWX6YvGHN/"
"gJApKpfGatKZAwdnUeZy+EUTuZnRzvSLOwOL6HsOFvuq4k3gQ5v5+"
"ZPfNxSO9T6JvrGzRxofo7edadxn/hqi6dkHU7koHNAjSD2AP==";
std::string messageHash;
BOOST_CHECK_EQUAL(
checkPoW(nonce, timestamp, ttl, pubkey, data, messageHash), false);
}
BOOST_AUTO_TEST_SUITE_END()

162
unit_test/storage.cpp Normal file
View file

@ -0,0 +1,162 @@
#include "Storage.hpp"
#include <iostream>
#include <string>
#include <boost/chrono.hpp>
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
struct StorageRAIIFixture {
StorageRAIIFixture() {
if (boost::filesystem::remove("storage.db")) {
std::cout << "Pre-test db removal" << std::endl;
}
}
~StorageRAIIFixture() {
if (boost::filesystem::remove("storage.db")) {
std::cout << "Post-test db removal" << std::endl;
}
}
};
BOOST_AUTO_TEST_SUITE(storage)
BOOST_AUTO_TEST_CASE(it_creates_the_database_file) {
StorageRAIIFixture fixture;
Storage storage(".");
BOOST_CHECK(boost::filesystem::exists("storage.db"));
}
BOOST_AUTO_TEST_CASE(it_stores_data_persistently) {
StorageRAIIFixture fixture;
const auto hash = "myhash";
const auto pubkey = "mypubkey";
const auto bytes = "bytesasstring";
const uint64_t ttl = 123456;
{
Storage storage(".");
BOOST_CHECK(storage.store(hash, pubkey, bytes, ttl));
// the database is closed when storage goes out of scope
}
{
// re-open the database
Storage storage(".");
std::vector<service_node::storage::Item> items;
const auto lastHash = "";
BOOST_CHECK(storage.retrieve(pubkey, items, lastHash));
BOOST_CHECK_EQUAL(items.size(), 1);
BOOST_CHECK_EQUAL(items[0].pubKey, pubkey);
BOOST_CHECK_EQUAL(items[0].hash, hash);
BOOST_CHECK_EQUAL((items[0].expirationTimestamp - items[0].timestamp),
(ttl * 1000));
BOOST_CHECK_EQUAL(items[0].bytes, bytes);
}
}
BOOST_AUTO_TEST_CASE(it_returns_false_when_storing_existing_hash) {
StorageRAIIFixture fixture;
const auto hash = "myhash";
const auto pubkey = "mypubkey";
const auto bytes = "bytesasstring";
const uint64_t ttl = 123456;
Storage storage(".");
BOOST_CHECK(storage.store(hash, pubkey, bytes, ttl));
// store using the same hash
BOOST_CHECK(storage.store(hash, pubkey, bytes, ttl) == false);
}
BOOST_AUTO_TEST_CASE(it_only_returns_entries_for_specified_pubkey) {
StorageRAIIFixture fixture;
Storage storage(".");
BOOST_CHECK(storage.store("hash0", "mypubkey", "bytesasstring0", 100000));
BOOST_CHECK(
storage.store("hash1", "otherpubkey", "bytesasstring1", 100000));
{
std::vector<service_node::storage::Item> items;
const auto lastHash = "";
BOOST_CHECK(storage.retrieve("mypubkey", items, lastHash));
BOOST_CHECK_EQUAL(items.size(), 1);
BOOST_CHECK_EQUAL(items[0].hash, "hash0");
}
{
std::vector<service_node::storage::Item> items;
const auto lastHash = "";
BOOST_CHECK(storage.retrieve("otherpubkey", items, lastHash));
BOOST_CHECK_EQUAL(items.size(), 1);
BOOST_CHECK_EQUAL(items[0].hash, "hash1");
}
}
BOOST_AUTO_TEST_CASE(it_returns_entries_older_than_lasthash) {
StorageRAIIFixture fixture;
Storage storage(".");
const size_t num_entries = 1000;
for (size_t i = 0; i < num_entries; i++) {
const auto hash = std::string("hash") + std::to_string(i);
storage.store(hash, "mypubkey", "bytesasstring", 100000);
}
{
std::vector<service_node::storage::Item> items;
const auto lastHash = "hash0";
BOOST_CHECK(storage.retrieve("mypubkey", items, lastHash));
BOOST_CHECK_EQUAL(items.size(), num_entries - 1);
BOOST_CHECK_EQUAL(items[0].hash, "hash1");
}
{
std::vector<service_node::storage::Item> items;
const auto lastHash =
std::string("hash") + std::to_string(num_entries / 2 - 1);
BOOST_CHECK(storage.retrieve("mypubkey", items, lastHash));
BOOST_CHECK_EQUAL(items.size(), num_entries / 2);
BOOST_CHECK_EQUAL(items[0].hash, "hash500");
}
}
BOOST_AUTO_TEST_CASE(it_removes_expired_entries) {
StorageRAIIFixture fixture;
const auto pubkey = "mypubkey";
Storage storage(".");
BOOST_CHECK(storage.store("hash0", pubkey, "bytesasstring0", 100000));
BOOST_CHECK(storage.store("hash1", pubkey, "bytesasstring0", 0));
{
std::vector<service_node::storage::Item> items;
const auto lastHash = "";
BOOST_CHECK(storage.retrieve(pubkey, items, lastHash));
BOOST_CHECK_EQUAL(items.size(), 2);
}
// the timer kicks in every 10 seconds
// give 100ms to perform the cleanup
std::cout << "waiting for cleanup timer..." << std::endl;
boost::this_thread::sleep_for(boost::chrono::milliseconds(10000 + 100));
{
std::vector<service_node::storage::Item> items;
const auto lastHash = "";
BOOST_CHECK(storage.retrieve(pubkey, items, lastHash));
BOOST_CHECK_EQUAL(items.size(), 1);
BOOST_CHECK_EQUAL(items[0].hash, "hash0");
}
}
BOOST_AUTO_TEST_SUITE_END()