mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 02:18:42 +00:00
feat: new JSON-RPC 2.0 RPC API (#7269)
* feat: add enum for JSON-RPC error codes * feat: new `tr_rpc_request_exec()` overload that accepts string * feat: add JSON-RPC parse error handling * feat: add logic for branching to JSON-RPC or legacy API * feat: error codes for existing errors strings * refactor: async handlers now take the done cb as parameter * feat: support non-batch JSON-RPC requests * feat: support batch JSON-RPC requests * refactor: move JSON-RPC error codes to header * test: new tests for JSON-RPC * refactor(webui): use jsonrpc api * docs: update docs for jsonrpc * fix: clang-tidy warning * perf: avoid copying callback in batch mode * code review: don't commit to dropping old RPC * chore: fix shadowed variable warnings
This commit is contained in:
@@ -30,7 +30,195 @@ namespace libtransmission::test
|
||||
|
||||
using RpcTest = SessionTest;
|
||||
|
||||
TEST_F(RpcTest, tagSync)
|
||||
TEST_F(RpcTest, EmptyRequest)
|
||||
{
|
||||
static auto constexpr Request = ""sv;
|
||||
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
Request,
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto const* const result = response_map->find_if<tr_variant::Map>(TR_KEY_result);
|
||||
EXPECT_EQ(result, nullptr);
|
||||
auto const* const error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
auto const error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, -32700); // don't use constants here in case they are wrong
|
||||
auto const error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Parse error"sv);
|
||||
auto const id = response_map->value_if<std::nullptr_t>(TR_KEY_id);
|
||||
EXPECT_TRUE(id);
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, NotArrayOrObject)
|
||||
{
|
||||
auto requests = std::vector<tr_variant>{};
|
||||
requests.emplace_back(12345);
|
||||
requests.emplace_back(0.5);
|
||||
requests.emplace_back("12345"sv);
|
||||
requests.emplace_back(nullptr);
|
||||
requests.emplace_back(true);
|
||||
|
||||
for (auto const& req : requests)
|
||||
{
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
req,
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto const result = response_map->find(TR_KEY_result);
|
||||
EXPECT_EQ(result, std::end(*response_map));
|
||||
auto const* const error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
auto const error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, -32600); // don't use constants here in case they are wrong
|
||||
auto const error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Invalid Request"sv);
|
||||
auto const error_data = error->find_if<tr_variant::Map>(TR_KEY_data);
|
||||
ASSERT_NE(error_data, nullptr);
|
||||
auto const error_string = error_data->value_if<std::string_view>(TR_KEY_errorString);
|
||||
ASSERT_TRUE(error_string);
|
||||
EXPECT_EQ(*error_string, "request must be an Array or Object"sv);
|
||||
auto const id = response_map->value_if<std::nullptr_t>(TR_KEY_id);
|
||||
EXPECT_TRUE(id);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, JsonRpcWrongVersion)
|
||||
{
|
||||
auto request_map = tr_variant::Map{ 3U };
|
||||
request_map.try_emplace(TR_KEY_jsonrpc, "1.0");
|
||||
request_map.try_emplace(TR_KEY_method, "session_stats");
|
||||
request_map.try_emplace(TR_KEY_id, 12345);
|
||||
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
std::move(request_map),
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto const result = response_map->find(TR_KEY_result);
|
||||
EXPECT_EQ(result, std::end(*response_map));
|
||||
auto const* const error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
auto const error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, -32600); // don't use constants here in case they are wrong
|
||||
auto const error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Invalid Request"sv);
|
||||
auto const error_data = error->find_if<tr_variant::Map>(TR_KEY_data);
|
||||
ASSERT_NE(error_data, nullptr);
|
||||
auto const error_string = error_data->value_if<std::string_view>(TR_KEY_errorString);
|
||||
ASSERT_TRUE(error_string);
|
||||
EXPECT_EQ(*error_string, "JSON-RPC version is not 2.0"sv);
|
||||
auto const id = response_map->value_if<std::nullptr_t>(TR_KEY_id);
|
||||
EXPECT_TRUE(id);
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, idSync)
|
||||
{
|
||||
auto ids = std::vector<tr_variant>{};
|
||||
ids.emplace_back(12345);
|
||||
ids.emplace_back(0.5);
|
||||
ids.emplace_back("12345"sv);
|
||||
ids.emplace_back(nullptr);
|
||||
|
||||
for (auto const& request_id : ids)
|
||||
{
|
||||
auto request_map = tr_variant::Map{ 3U };
|
||||
request_map.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request_map.try_emplace(TR_KEY_method, "session-stats");
|
||||
request_map[TR_KEY_id].merge(request_id); // copy
|
||||
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
std::move(request_map),
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto const* const result = response_map->find_if<tr_variant::Map>(TR_KEY_result);
|
||||
EXPECT_NE(result, nullptr);
|
||||
auto const error = response_map->find(TR_KEY_error);
|
||||
EXPECT_EQ(error, std::end(*response_map));
|
||||
switch (request_id.index())
|
||||
{
|
||||
case tr_variant::IntIndex:
|
||||
EXPECT_EQ(request_id.value_if<int64_t>(), response_map->value_if<int64_t>(TR_KEY_id));
|
||||
break;
|
||||
case tr_variant::DoubleIndex:
|
||||
EXPECT_EQ(request_id.value_if<double>(), response_map->value_if<double>(TR_KEY_id));
|
||||
break;
|
||||
case tr_variant::StringIndex:
|
||||
EXPECT_EQ(request_id.value_if<std::string_view>(), response_map->value_if<std::string_view>(TR_KEY_id));
|
||||
break;
|
||||
case tr_variant::NullIndex:
|
||||
EXPECT_EQ(request_id.value_if<std::nullptr_t>(), response_map->value_if<std::nullptr_t>(TR_KEY_id));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, idWrongType)
|
||||
{
|
||||
auto ids = std::vector<tr_variant>{};
|
||||
ids.emplace_back(tr_variant::Map{});
|
||||
ids.emplace_back(tr_variant::Vector{});
|
||||
ids.emplace_back(true);
|
||||
|
||||
for (auto const& request_id : ids)
|
||||
{
|
||||
auto request_map = tr_variant::Map{ 3U };
|
||||
request_map.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request_map.try_emplace(TR_KEY_method, "session_stats");
|
||||
request_map[TR_KEY_id].merge(request_id); // copy
|
||||
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
std::move(request_map),
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto const result = response_map->find(TR_KEY_result);
|
||||
EXPECT_EQ(result, std::end(*response_map));
|
||||
auto const error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
auto const error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, -32600); // don't use constants here in case they are wrong
|
||||
auto const error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Invalid Request"sv);
|
||||
auto const error_data = error->find_if<tr_variant::Map>(TR_KEY_data);
|
||||
ASSERT_NE(error_data, nullptr);
|
||||
auto const error_string = error_data->value_if<std::string_view>(TR_KEY_errorString);
|
||||
ASSERT_TRUE(error_string);
|
||||
EXPECT_EQ(*error_string, "id type must be String, Number, or Null"sv);
|
||||
auto const id = response_map->value_if<std::nullptr_t>(TR_KEY_id);
|
||||
EXPECT_TRUE(id);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, tagSyncLegacy)
|
||||
{
|
||||
auto request_map = tr_variant::Map{ 2U };
|
||||
request_map.try_emplace(TR_KEY_method, "session-stats");
|
||||
@@ -39,7 +227,7 @@ TEST_F(RpcTest, tagSync)
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
tr_variant{ std::move(request_map) },
|
||||
std::move(request_map),
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
@@ -52,7 +240,67 @@ TEST_F(RpcTest, tagSync)
|
||||
EXPECT_EQ(*tag, 12345);
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, tagAsync)
|
||||
TEST_F(RpcTest, idAsync)
|
||||
{
|
||||
auto ids = std::vector<tr_variant>{};
|
||||
ids.emplace_back(12345);
|
||||
ids.emplace_back(0.5);
|
||||
ids.emplace_back("12345"sv);
|
||||
ids.emplace_back(nullptr);
|
||||
|
||||
for (auto const& request_id : ids)
|
||||
{
|
||||
auto* tor = zeroTorrentInit(ZeroTorrentState::Complete);
|
||||
EXPECT_NE(nullptr, tor);
|
||||
|
||||
auto request_map = tr_variant::Map{ 3U };
|
||||
request_map.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request_map.try_emplace(TR_KEY_method, "torrent-rename-path");
|
||||
request_map[TR_KEY_id].merge(request_id); // copy
|
||||
|
||||
auto params_map = tr_variant::Map{ 2U };
|
||||
params_map.try_emplace(TR_KEY_path, "files-filled-with-zeroes/512");
|
||||
params_map.try_emplace(TR_KEY_name, "512_test");
|
||||
request_map.try_emplace(TR_KEY_params, std::move(params_map));
|
||||
|
||||
auto promise = std::promise<tr_variant>{};
|
||||
auto future = promise.get_future();
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
std::move(request_map),
|
||||
[&promise](tr_session* /*session*/, tr_variant&& resp) { promise.set_value(std::move(resp)); });
|
||||
auto const response = future.get();
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto const result = response_map->find_if<tr_variant::Map>(TR_KEY_result);
|
||||
EXPECT_NE(result, nullptr);
|
||||
auto const error = response_map->find(TR_KEY_error);
|
||||
EXPECT_EQ(error, std::end(*response_map));
|
||||
switch (request_id.index())
|
||||
{
|
||||
case tr_variant::IntIndex:
|
||||
EXPECT_EQ(request_id.value_if<int64_t>(), response_map->value_if<int64_t>(TR_KEY_id));
|
||||
break;
|
||||
case tr_variant::DoubleIndex:
|
||||
EXPECT_EQ(request_id.value_if<double>(), response_map->value_if<double>(TR_KEY_id));
|
||||
break;
|
||||
case tr_variant::StringIndex:
|
||||
EXPECT_EQ(request_id.value_if<std::string_view>(), response_map->value_if<std::string_view>(TR_KEY_id));
|
||||
break;
|
||||
case tr_variant::NullIndex:
|
||||
EXPECT_EQ(request_id.value_if<std::nullptr_t>(), response_map->value_if<std::nullptr_t>(TR_KEY_id));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// cleanup
|
||||
tr_torrentRemove(tor, false, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, tagAsyncLegacy)
|
||||
{
|
||||
auto* tor = zeroTorrentInit(ZeroTorrentState::Complete);
|
||||
EXPECT_NE(nullptr, tor);
|
||||
@@ -70,7 +318,7 @@ TEST_F(RpcTest, tagAsync)
|
||||
auto future = promise.get_future();
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
tr_variant{ std::move(request_map) },
|
||||
std::move(request_map),
|
||||
[&promise](tr_session* /*session*/, tr_variant&& resp) { promise.set_value(std::move(resp)); });
|
||||
auto const response = future.get();
|
||||
|
||||
@@ -87,7 +335,83 @@ TEST_F(RpcTest, tagAsync)
|
||||
tr_torrentRemove(tor, false, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, NotificationSync)
|
||||
{
|
||||
auto request_map = tr_variant::Map{ 2U };
|
||||
request_map.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request_map.try_emplace(TR_KEY_method, "session_stats");
|
||||
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
std::move(request_map),
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
EXPECT_FALSE(response.has_value());
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, NotificationAsync)
|
||||
{
|
||||
auto* tor = zeroTorrentInit(ZeroTorrentState::Complete);
|
||||
EXPECT_NE(nullptr, tor);
|
||||
|
||||
auto request_map = tr_variant::Map{ 2U };
|
||||
request_map.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request_map.try_emplace(TR_KEY_method, "torrent_rename_path");
|
||||
|
||||
auto params_map = tr_variant::Map{ 2U };
|
||||
params_map.try_emplace(TR_KEY_path, "files-filled-with-zeroes/512");
|
||||
params_map.try_emplace(TR_KEY_name, "512_test");
|
||||
request_map.try_emplace(TR_KEY_params, std::move(params_map));
|
||||
|
||||
auto promise = std::promise<tr_variant>{};
|
||||
auto future = promise.get_future();
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
std::move(request_map),
|
||||
[&promise](tr_session* /*session*/, tr_variant&& resp) { promise.set_value(std::move(resp)); });
|
||||
auto const response = future.get();
|
||||
|
||||
EXPECT_FALSE(response.has_value());
|
||||
|
||||
// cleanup
|
||||
tr_torrentRemove(tor, false, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, tagNoHandler)
|
||||
{
|
||||
auto request_map = tr_variant::Map{ 3U };
|
||||
request_map.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request_map.try_emplace(TR_KEY_method, "sdgdhsgg");
|
||||
request_map.try_emplace(TR_KEY_id, 12345);
|
||||
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
std::move(request_map),
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto const jsonrpc = response_map->value_if<std::string_view>(TR_KEY_jsonrpc);
|
||||
ASSERT_TRUE(jsonrpc);
|
||||
EXPECT_EQ(*jsonrpc, JsonRpc::Version);
|
||||
auto const result = response_map->find_if<tr_variant::Map>(TR_KEY_result);
|
||||
EXPECT_EQ(result, nullptr);
|
||||
auto const error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
auto const error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, JsonRpc::Error::METHOD_NOT_FOUND);
|
||||
auto const error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Method not found"sv);
|
||||
auto const id = response_map->value_if<int64_t>(TR_KEY_id);
|
||||
ASSERT_TRUE(id);
|
||||
EXPECT_EQ(*id, 12345);
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, tagNoHandlerLegacy)
|
||||
{
|
||||
auto request_map = tr_variant::Map{ 2U };
|
||||
request_map.try_emplace(TR_KEY_method, "sdgdhsgg");
|
||||
@@ -96,7 +420,7 @@ TEST_F(RpcTest, tagNoHandler)
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
tr_variant{ std::move(request_map) },
|
||||
std::move(request_map),
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto const* const response_map = response.get_if<tr_variant::Map>();
|
||||
@@ -109,6 +433,154 @@ TEST_F(RpcTest, tagNoHandler)
|
||||
EXPECT_EQ(*tag, 12345);
|
||||
}
|
||||
|
||||
TEST_F(RpcTest, batch)
|
||||
{
|
||||
auto request_vec = tr_variant::Vector{};
|
||||
request_vec.reserve(8U);
|
||||
|
||||
auto request = tr_variant::Map{ 3U };
|
||||
request.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request.try_emplace(TR_KEY_method, "session-stats");
|
||||
request.try_emplace(TR_KEY_id, 12345);
|
||||
request_vec.emplace_back(std::move(request));
|
||||
|
||||
request = tr_variant::Map{ 2U };
|
||||
request.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request.try_emplace(TR_KEY_method, "session-set");
|
||||
request_vec.emplace_back(std::move(request));
|
||||
|
||||
request = tr_variant::Map{ 3U };
|
||||
request.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request.try_emplace(TR_KEY_method, "session-stats");
|
||||
request.try_emplace(TR_KEY_id, "12345"sv);
|
||||
request_vec.emplace_back(std::move(request));
|
||||
|
||||
request = tr_variant::Map{ 1U };
|
||||
request.try_emplace(tr_quark_new("foo"sv), "boo"sv);
|
||||
request_vec.emplace_back(std::move(request));
|
||||
|
||||
request_vec.emplace_back(1);
|
||||
|
||||
request = tr_variant::Map{ 3U };
|
||||
request.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request.try_emplace(TR_KEY_method, "dnfsojnsdkjf");
|
||||
request.try_emplace(TR_KEY_id, 12345);
|
||||
request_vec.emplace_back(std::move(request));
|
||||
|
||||
request = tr_variant::Map{ 1U };
|
||||
request.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request.try_emplace(TR_KEY_method, "dnfsojnsdkjf");
|
||||
request_vec.emplace_back(std::move(request));
|
||||
|
||||
request = tr_variant::Map{ 2U };
|
||||
request.try_emplace(TR_KEY_method, "session-stats");
|
||||
request.try_emplace(TR_KEY_tag, 12345);
|
||||
request_vec.emplace_back(std::move(request));
|
||||
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
std::move(request_vec),
|
||||
[&response](tr_session* /*session*/, tr_variant&& resp) { response = std::move(resp); });
|
||||
|
||||
auto* const response_vec_ptr = response.get_if<tr_variant::Vector>();
|
||||
ASSERT_NE(response_vec_ptr, nullptr);
|
||||
auto const& response_vec = *response_vec_ptr;
|
||||
|
||||
ASSERT_EQ(std::size(response_vec), 6U);
|
||||
|
||||
auto const* response_map = response_vec[0].get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto const* result = response_map->find_if<tr_variant::Map>(TR_KEY_result);
|
||||
EXPECT_NE(result, nullptr);
|
||||
auto error_it = response_map->find(TR_KEY_error);
|
||||
EXPECT_EQ(error_it, std::end(*response_map));
|
||||
auto id_int = response_map->value_if<int64_t>(TR_KEY_id);
|
||||
ASSERT_TRUE(id_int);
|
||||
EXPECT_EQ(*id_int, 12345);
|
||||
|
||||
response_map = response_vec[1].get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
result = response_map->find_if<tr_variant::Map>(TR_KEY_result);
|
||||
EXPECT_NE(result, nullptr);
|
||||
error_it = response_map->find(TR_KEY_error);
|
||||
EXPECT_EQ(error_it, std::end(*response_map));
|
||||
auto id_str = response_map->value_if<std::string_view>(TR_KEY_id);
|
||||
ASSERT_TRUE(id_str);
|
||||
EXPECT_EQ(*id_str, "12345"sv);
|
||||
|
||||
response_map = response_vec[2].get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto result_it = response_map->find(TR_KEY_result);
|
||||
EXPECT_EQ(result_it, std::end(*response_map));
|
||||
auto error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
auto error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, -32600); // don't use constants here in case they are wrong
|
||||
auto error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Invalid Request"sv);
|
||||
auto id_null = response_map->value_if<std::nullptr_t>(TR_KEY_id);
|
||||
EXPECT_TRUE(id_null);
|
||||
|
||||
response_map = response_vec[3].get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
result_it = response_map->find(TR_KEY_result);
|
||||
EXPECT_EQ(result_it, std::end(*response_map));
|
||||
error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, -32600); // don't use constants here in case they are wrong
|
||||
error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Invalid Request"sv);
|
||||
auto error_data = error->find_if<tr_variant::Map>(TR_KEY_data);
|
||||
ASSERT_NE(error_data, nullptr);
|
||||
auto error_string = error_data->value_if<std::string_view>(TR_KEY_errorString);
|
||||
ASSERT_TRUE(error_string);
|
||||
EXPECT_EQ(*error_string, "request must be an Object"sv);
|
||||
id_null = response_map->value_if<std::nullptr_t>(TR_KEY_id);
|
||||
EXPECT_TRUE(id_null);
|
||||
|
||||
response_map = response_vec[4].get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
result_it = response_map->find(TR_KEY_result);
|
||||
EXPECT_EQ(result_it, std::end(*response_map));
|
||||
error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, -32601); // don't use constants here in case they are wrong
|
||||
error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Method not found"sv);
|
||||
id_int = response_map->value_if<int64_t>(TR_KEY_id);
|
||||
ASSERT_TRUE(id_int);
|
||||
EXPECT_EQ(*id_int, 12345);
|
||||
|
||||
response_map = response_vec[5].get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
result_it = response_map->find(TR_KEY_result);
|
||||
EXPECT_EQ(result_it, std::end(*response_map));
|
||||
error = response_map->find_if<tr_variant::Map>(TR_KEY_error);
|
||||
ASSERT_NE(error, nullptr);
|
||||
error_code = error->value_if<int64_t>(TR_KEY_code);
|
||||
ASSERT_TRUE(error_code);
|
||||
EXPECT_EQ(*error_code, -32600); // don't use constants here in case they are wrong
|
||||
error_message = error->value_if<std::string_view>(TR_KEY_message);
|
||||
ASSERT_TRUE(error_message);
|
||||
EXPECT_EQ(*error_message, "Invalid Request"sv);
|
||||
error_data = error->find_if<tr_variant::Map>(TR_KEY_data);
|
||||
ASSERT_NE(error_data, nullptr);
|
||||
error_string = error_data->value_if<std::string_view>(TR_KEY_errorString);
|
||||
ASSERT_TRUE(error_string);
|
||||
EXPECT_EQ(*error_string, "JSON-RPC version is not 2.0"sv);
|
||||
id_null = response_map->value_if<std::nullptr_t>(TR_KEY_id);
|
||||
EXPECT_TRUE(id_null);
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
@@ -118,8 +590,10 @@ TEST_F(RpcTest, sessionGet)
|
||||
auto* tor = zeroTorrentInit(ZeroTorrentState::NoFiles);
|
||||
EXPECT_NE(nullptr, tor);
|
||||
|
||||
auto request_map = tr_variant::Map{ 1U };
|
||||
auto request_map = tr_variant::Map{ 3U };
|
||||
request_map.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request_map.try_emplace(TR_KEY_method, "session-get"sv);
|
||||
request_map.try_emplace(TR_KEY_id, 12345);
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
session_,
|
||||
@@ -128,7 +602,7 @@ TEST_F(RpcTest, sessionGet)
|
||||
|
||||
auto* response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto* args_map = response_map->find_if<tr_variant::Map>(TR_KEY_arguments);
|
||||
auto* args_map = response_map->find_if<tr_variant::Map>(TR_KEY_result);
|
||||
ASSERT_NE(args_map, nullptr);
|
||||
|
||||
// what we expected
|
||||
@@ -231,15 +705,17 @@ TEST_F(RpcTest, torrentGet)
|
||||
auto* tor = zeroTorrentInit(ZeroTorrentState::NoFiles);
|
||||
EXPECT_NE(nullptr, tor);
|
||||
|
||||
auto request = tr_variant::Map{ 1U };
|
||||
auto request = tr_variant::Map{ 3U };
|
||||
|
||||
request.try_emplace(TR_KEY_method, "torrent-get");
|
||||
request.try_emplace(TR_KEY_jsonrpc, JsonRpc::Version);
|
||||
request.try_emplace(TR_KEY_method, "torrent-get"sv);
|
||||
request.try_emplace(TR_KEY_id, 12345);
|
||||
|
||||
auto args_in = tr_variant::Map{ 1U };
|
||||
auto params = tr_variant::Map{ 1U };
|
||||
auto fields = tr_variant::Vector{};
|
||||
fields.emplace_back(tr_quark_get_string_view(TR_KEY_id));
|
||||
args_in.try_emplace(TR_KEY_fields, std::move(fields));
|
||||
request.try_emplace(TR_KEY_arguments, std::move(args_in));
|
||||
params.try_emplace(TR_KEY_fields, std::move(fields));
|
||||
request.try_emplace(TR_KEY_params, std::move(params));
|
||||
|
||||
auto response = tr_variant{};
|
||||
tr_rpc_request_exec(
|
||||
@@ -249,10 +725,10 @@ TEST_F(RpcTest, torrentGet)
|
||||
|
||||
auto* response_map = response.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(response_map, nullptr);
|
||||
auto* args_out = response_map->find_if<tr_variant::Map>(TR_KEY_arguments);
|
||||
ASSERT_NE(args_out, nullptr);
|
||||
auto* result = response_map->find_if<tr_variant::Map>(TR_KEY_result);
|
||||
ASSERT_NE(result, nullptr);
|
||||
|
||||
auto* torrents = args_out->find_if<tr_variant::Vector>(TR_KEY_torrents);
|
||||
auto* torrents = result->find_if<tr_variant::Vector>(TR_KEY_torrents);
|
||||
ASSERT_NE(torrents, nullptr);
|
||||
EXPECT_EQ(1UL, std::size(*torrents));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user