diff --git a/tests/unit/parsec/agent/runners/lua/read_lock_test.cpp b/tests/unit/parsec/agent/runners/lua/read_lock_test.cpp new file mode 100644 index 000000000..b3f355467 --- /dev/null +++ b/tests/unit/parsec/agent/runners/lua/read_lock_test.cpp @@ -0,0 +1,136 @@ +// Copyright (c) 2021 MIT Digital Currency Initiative, +// Federal Reserve Bank of Boston +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "../../../util.hpp" +#include "crypto/sha256.h" +#include "parsec/agent/impl.hpp" +#include "parsec/agent/runners/lua/impl.hpp" +#include "parsec/broker/impl.hpp" +#include "parsec/directory/impl.hpp" +#include "parsec/runtime_locking_shard/impl.hpp" +#include "parsec/ticket_machine/impl.hpp" +#include "parsec/util.hpp" +#include "util/common/keys.hpp" +#include "util/serialization/buffer_serializer.hpp" +#include "util/serialization/format.hpp" + +#include +#include +#include +#include +#include +#include + +TEST(lua_runner_test, lua_write_lock_test) { + auto log = std::make_shared( + cbdc::logging::log_level::trace); + lua_State* L = luaL_newstate(); + luaL_openlibs(L); + luaL_dofile(L, + "../tests/unit/parsec/agent/runners/lua/test_write_locks.lua"); + lua_getglobal(L, "gen_bytecode"); + ASSERT_EQ(lua_pcall(L, 0, 1, 0), 0); + auto contract = cbdc::buffer::from_hex(lua_tostring(L, -1)).value(); + auto func = cbdc::buffer::from_hex(contract.to_hex()).value(); + auto param = cbdc::buffer(); + auto cfg = cbdc::parsec::config(); + + auto result_cb = [&](cbdc::parsec::agent::runner::interface:: + run_return_type /* value */) { + return; + }; + + std::promise write_lock_promise; + auto write_lock_future = write_lock_promise.get_future(); + auto try_lock_cb + = [&](const cbdc::parsec::broker::key_type& key, + cbdc::parsec::broker::lock_type locktype, + const cbdc::parsec::broker::interface::try_lock_callback_type& + /* res_cb */) -> bool { + // Cannot use ASSERT here because it does not satisfy return + // requirements so we use expect + if(std::string("W").compare(key.c_str()) == 0) { + EXPECT_TRUE(locktype == cbdc::parsec::broker::lock_type::write); + write_lock_promise.set_value(); + } else { + // Cannot use FAIL() here because it expands to a return statement + // which does not satisfy the requirements of a try_lock_callback + // so we improvise + EXPECT_FALSE(true); + } + return true; + }; + + auto runner + = cbdc::parsec::agent::runner::lua_runner(log, + cfg, + std::move(func), + std::move(param), + false, + std::move(result_cb), + std::move(try_lock_cb), + nullptr, + nullptr, + 0); + auto res = runner.run(); + write_lock_future.get(); + ASSERT_TRUE(res); +} + +TEST(lua_runner_test, lua_read_lock_test) { + auto log = std::make_shared( + cbdc::logging::log_level::trace); + lua_State* L = luaL_newstate(); + luaL_openlibs(L); + luaL_dofile(L, + "../tests/unit/parsec/agent/runners/lua/test_read_locks.lua"); + lua_getglobal(L, "gen_bytecode"); + ASSERT_EQ(lua_pcall(L, 0, 1, 0), 0); + auto contract = cbdc::buffer::from_hex(lua_tostring(L, -1)).value(); + auto func = cbdc::buffer::from_hex(contract.to_hex()).value(); + auto param = cbdc::buffer(); + auto cfg = cbdc::parsec::config(); + + auto result_cb = [&](cbdc::parsec::agent::runner::interface:: + run_return_type /* value */) { + return; + }; + + std::promise read_lock_promise; + auto read_lock_future = read_lock_promise.get_future(); + auto try_lock_cb + = [&](const cbdc::parsec::broker::key_type& key, + cbdc::parsec::broker::lock_type locktype, + const cbdc::parsec::broker::interface::try_lock_callback_type& + /* res_cb */) -> bool { + // Cannot use ASSERT here because it does not satisfy return + // requirements so we use expect + if(std::string("R").compare(key.c_str()) == 0) { + EXPECT_TRUE(locktype == cbdc::parsec::broker::lock_type::read); + read_lock_promise.set_value(); + } else { + // Cannot use FAIL() here because it expands to a return statement + // which does not satisfy the requirements of a try_lock_callback + // so we improvise + EXPECT_FALSE(true); + } + return true; + }; + + auto runner + = cbdc::parsec::agent::runner::lua_runner(log, + cfg, + std::move(func), + std::move(param), + false, + std::move(result_cb), + std::move(try_lock_cb), + nullptr, + nullptr, + 0); + auto res = runner.run(); + read_lock_future.get(); + ASSERT_TRUE(res); +} diff --git a/tests/unit/parsec/agent/runners/lua/test_read_locks.lua b/tests/unit/parsec/agent/runners/lua/test_read_locks.lua new file mode 100644 index 000000000..cbb34642d --- /dev/null +++ b/tests/unit/parsec/agent/runners/lua/test_read_locks.lua @@ -0,0 +1,17 @@ +function gen_bytecode() + pay_contract = function(param) + Locks = { + READ = 0, + WRITE = 1, + } + data = coroutine.yield("R", Locks.READ) + return "Done" + end + c = string.dump(pay_contract, true) + t = {} + for i = 1, #c do + t[#t + 1] = string.format("%02x", string.byte(c, i)) + end + + return table.concat(t) +end diff --git a/tests/unit/parsec/agent/runners/lua/test_write_locks.lua b/tests/unit/parsec/agent/runners/lua/test_write_locks.lua new file mode 100644 index 000000000..5ad423256 --- /dev/null +++ b/tests/unit/parsec/agent/runners/lua/test_write_locks.lua @@ -0,0 +1,17 @@ +function gen_bytecode() + pay_contract = function(param) + Locks = { + READ = 0, + WRITE = 1, + } + data2 = coroutine.yield("W", Locks.WRITE) + return "Done" + end + c = string.dump(pay_contract, true) + t = {} + for i = 1, #c do + t[#t + 1] = string.format("%02x", string.byte(c, i)) + end + + return table.concat(t) +end diff --git a/tests/unit/parsec/agent/runners/lua/write_lock_test.cpp b/tests/unit/parsec/agent/runners/lua/write_lock_test.cpp new file mode 100644 index 000000000..d503a72d5 --- /dev/null +++ b/tests/unit/parsec/agent/runners/lua/write_lock_test.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2021 MIT Digital Currency Initiative, +// Federal Reserve Bank of Boston +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "../../../util.hpp" +#include "crypto/sha256.h" +#include "parsec/agent/impl.hpp" +#include "parsec/agent/runners/lua/impl.hpp" +#include "parsec/broker/impl.hpp" +#include "parsec/directory/impl.hpp" +#include "parsec/runtime_locking_shard/impl.hpp" +#include "parsec/ticket_machine/impl.hpp" +#include "parsec/util.hpp" +#include "util/common/keys.hpp" +#include "util/serialization/buffer_serializer.hpp" +#include "util/serialization/format.hpp" + +#include +#include +#include +#include +#include +#include + +TEST(lua_runner_test, lua_read_lock_test) { + auto log = std::make_shared( + cbdc::logging::log_level::trace); + lua_State* L = luaL_newstate(); + luaL_openlibs(L); + luaL_dofile(L, + "../tests/unit/parsec/agent/runners/lua/test_write_locks.lua"); + lua_getglobal(L, "gen_bytecode"); + ASSERT_EQ(lua_pcall(L, 0, 1, 0), 0); + auto contract = cbdc::buffer::from_hex(lua_tostring(L, -1)).value(); + auto func = cbdc::buffer::from_hex(contract.to_hex()).value(); + auto param = cbdc::buffer(); + auto cfg = cbdc::parsec::config(); + + auto result_cb = [&](cbdc::parsec::agent::runner::interface:: + run_return_type /* value */) { + return; + }; + + std::atomic lock_count = 0; + std::promise write_lock_promise; + std::promise read_lock_promise; + auto write_lock_future = write_lock_promise.get_future(); + auto read_lock_future = read_lock_promise.get_future(); + auto try_lock_cb + = [&](const cbdc::parsec::broker::key_type& key, + cbdc::parsec::broker::lock_type locktype, + const cbdc::parsec::broker::interface::try_lock_callback_type& + /* res_cb */) -> bool { + // Cannot use ASSERT here because it does not satisfy return requirements + // so we use expect + log->trace("Got lock for key:", key.c_str()); + if(std::string("W").compare(key.c_str()) == 0) { + log->trace("Got write lock"); + EXPECT_TRUE(locktype == cbdc::parsec::broker::lock_type::write); + lock_count++; + write_lock_promise.set_value(); + } else if(std::string("R").compare(key.c_str()) == 0) { + log->trace("Got read lock"); + EXPECT_TRUE(locktype == cbdc::parsec::broker::lock_type::read); + lock_count++; + read_lock_promise.set_value(); + } else { + // Cannot use FAIL() here because it expands to a return statement + // which does not satisfy the requirements of a try_lock_callback + // so we improvise + EXPECT_FALSE(true); + } + return true; + }; + + auto runner + = cbdc::parsec::agent::runner::lua_runner(log, + cfg, + std::move(func), + std::move(param), + false, + std::move(result_cb), + std::move(try_lock_cb), + nullptr, + nullptr, + 0); + auto res = runner.run(); + write_lock_future.get(); + read_lock_future.get(); + ASSERT_EQ(lock_count, 2); + ASSERT_TRUE(res); +}