From c409a4e04a0b9e62392a4846c5ea46fdb8cf55e9 Mon Sep 17 00:00:00 2001 From: "Andreas C. Osowski" Date: Wed, 18 Apr 2018 23:39:20 +0200 Subject: [PATCH] hub: complete GetBalance implementation with test --- hub/commands/get_balance.cc | 49 +++++++++++++++++++----- hub/commands/tests/runner.h | 48 +++++++++++++++++++++++ hub/commands/tests/test_create_user.cc | 47 ++++++----------------- hub/commands/tests/test_get_balance.cc | 53 ++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 45 deletions(-) create mode 100644 hub/commands/tests/runner.h create mode 100644 hub/commands/tests/test_get_balance.cc diff --git a/hub/commands/get_balance.cc b/hub/commands/get_balance.cc index e935053..7547ae7 100644 --- a/hub/commands/get_balance.cc +++ b/hub/commands/get_balance.cc @@ -1,33 +1,64 @@ #include "get_balance.h" +#include + #include #include #include #include "proto/hub.pb.h" #include "schema/schema.h" - #include "hub/db/db.h" #include "hub/stats/session.h" #include "helper.h" + using namespace sqlpp; +namespace { +SQLPP_ALIAS_PROVIDER(total); +} + namespace iota { namespace cmd { -grpc::Status GetBalance::doProcess(const iota::rpc::GetBalanceRequest* request, - iota::rpc::GetBalanceReply* response) noexcept { +grpc::Status GetBalance::doProcess( + const iota::rpc::GetBalanceRequest* request, + iota::rpc::GetBalanceReply* response) noexcept { db::sql::UserAccount acc; - db::sql::UserAddressBalance bal; + db::sql::UserAccountBalance bal; + + uint64_t userId; + + auto& connection = db::DBManager::get().connection(); + + // Get userId for identifier + { + const auto result = connection( + select(acc.id).from(acc).where(acc.identifier == request->userid())); + + if (result.empty()) { + return grpc::Status( + grpc::StatusCode::FAILED_PRECONDITION, "", + errorToString(iota::rpc::ErrorCode::USER_DOES_NOT_EXIST)); + } + + userId = result.front().id; + } - auto& conn = db::DBManager::get().connection(); + // Summarise all amounts for user_account_balance changes + { + const auto result = connection(select(sum(bal.amount).as(total)) + .from(bal) + .where(bal.userAccount == userId)); - auto userId = conn(select(acc.id).from(acc).where(acc.identifier == request->userid())).first(); - - LOG(ERROR) << userId; - + if (result.empty()) { + return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "", + errorToString(iota::rpc::ErrorCode::UNKNOWN)); + } + response->set_available(result.front().total); + } return grpc::Status::OK; } diff --git a/hub/commands/tests/runner.h b/hub/commands/tests/runner.h new file mode 100644 index 0000000..0c1c661 --- /dev/null +++ b/hub/commands/tests/runner.h @@ -0,0 +1,48 @@ +#ifndef __HUB_COMMANDS_TESTS_RUNNER_H_ +#define __HUB_COMMANDS_TESTS_RUNNER_H_ + +#include + +#include "hub/commands/create_user.h" +#include "hub/db/db.h" +#include "hub/stats/session.h" +#include "proto/hub.pb.h" + +namespace iota { +class CommandTest : public ::testing::Test { + public: + virtual void SetUp() { + auto db = iota::db::DBManager::get(); + db.resetConnection(); + db.loadSchema(true); + + _session = std::make_shared(); + } + + virtual void TearDown() { _session = nullptr; } + + std::shared_ptr session() { return _session; } + + grpc::Status createUser(std::shared_ptr session, + std::string username) { + rpc::CreateUserRequest req; + rpc::CreateUserReply res; + + req.set_userid(std::move(username)); + cmd::CreateUser command(std::move(session)); + return command.doProcess(&req, &res); + } + + rpc::Error errorFromStatus(grpc::Status& status) { + rpc::Error err; + err.ParseFromString(status.error_details()); + + return err; + } + + private: + std::shared_ptr _session; +}; + +} // namespace iota +#endif /* __HUB_COMMANDS_TESTS_RUNNER_H_ */ diff --git a/hub/commands/tests/test_create_user.cc b/hub/commands/tests/test_create_user.cc index 1bf3b70..bcc5bfe 100644 --- a/hub/commands/tests/test_create_user.cc +++ b/hub/commands/tests/test_create_user.cc @@ -1,4 +1,5 @@ #include + #include #include @@ -7,36 +8,23 @@ #include "hub/commands/create_user.h" #include "hub/db/db.h" -#include "hub/stats/session.h" + +#include "runner.h" using namespace iota; using namespace sqlpp; namespace { -class CommandTest : public ::testing::Test { - public: - virtual void SetUp() { - auto db = iota::db::DBManager::get(); - db.resetConnection(); - db.loadSchema(true); - } -}; +class CreateUserTest : public CommandTest {}; -TEST_F(CommandTest, ErrorOnDuplicate) { - rpc::CreateUserRequest req; - rpc::CreateUserReply res; - rpc::Error err; +TEST_F(CreateUserTest, ErrorOnDuplicate) { db::sql::UserAccount tbl; - auto session = std::make_shared(); auto& conn = iota::db::DBManager::get().connection(); - req.set_identifier("User1"); - - cmd::CreateUser command(session); - command.doProcess(&req, &res); - auto status = command.doProcess(&req, &res); - err.ParseFromString(status.error_details()); + createUser(session(), "User1"); + auto status = createUser(session(), "User1"); + auto err = errorFromStatus(status); EXPECT_EQ(grpc::StatusCode::FAILED_PRECONDITION, status.error_code()); EXPECT_EQ(err.code(), rpc::ErrorCode::USER_EXISTS); @@ -45,26 +33,13 @@ TEST_F(CommandTest, ErrorOnDuplicate) { .count); } -TEST_F(CommandTest, CreateUsers) { - rpc::CreateUserRequest req; - rpc::CreateUserReply res; +TEST_F(CreateUserTest, CreateUsers) { db::sql::UserAccount tbl; - auto session = std::make_shared(); auto& conn = iota::db::DBManager::get().connection(); - req.set_identifier("User1"); - - { - cmd::CreateUser command(session); - command.doProcess(&req, &res); - } - - req.set_identifier("User2"); - { - cmd::CreateUser command(session); - command.doProcess(&req, &res); - } + EXPECT_TRUE(createUser(session(), "User1").ok()); + EXPECT_TRUE(createUser(session(), "User2").ok()); EXPECT_EQ(2, conn(select(count(tbl.identifier)).from(tbl).unconditionally()) .front() diff --git a/hub/commands/tests/test_get_balance.cc b/hub/commands/tests/test_get_balance.cc new file mode 100644 index 0000000..4ddf864 --- /dev/null +++ b/hub/commands/tests/test_get_balance.cc @@ -0,0 +1,53 @@ +#include +#include +#include + +#include "proto/hub.pb.h" +#include "schema/schema.h" + +#include "hub/db/db.h" +#include "hub/stats/session.h" +#include "hub/commands/get_balance.h" + +#include "runner.h" + +using namespace iota; +using namespace sqlpp; + +namespace { +class GetBalanceTest : public CommandTest {}; + +TEST_F(GetBalanceTest, UnknownUserShouldFail) { + rpc::GetBalanceRequest req; + rpc::GetBalanceReply res; + + req.set_userid("User1"); + cmd::GetBalance command(session()); + + auto status = command.doProcess(&req, &res); + + EXPECT_FALSE(status.ok()); + + auto err = errorFromStatus(status); + EXPECT_EQ(err.code(), rpc::ErrorCode::USER_DOES_NOT_EXIST); +} + +TEST_F(GetBalanceTest, NewUserHasZeroBalance) { + rpc::GetBalanceRequest req; + rpc::GetBalanceReply res; + rpc::Error err; + + constexpr auto username = "User1"; + + createUser(session(), username); + + req.set_userid("User1"); + + cmd::GetBalance command(session()); + + EXPECT_TRUE(command.doProcess(&req, &res).ok()); + + EXPECT_EQ(0, res.available()); +} + +}; // namespace