Skip to content
Snippets Groups Projects
Commit d0510dcb authored by Seva's avatar Seva Committed by Adrien Béraud
Browse files

http: add send json & unit test

parent 6f87e9db
No related branches found
No related tags found
No related merge requests found
......@@ -382,7 +382,7 @@ if (OPENDHT_TESTS)
${CMAKE_THREAD_LIBS_INIT}
${CPPUNIT_LIBRARIES}
${GNUTLS_LIBRARIES}
ssl crypto
ssl crypto jsoncpp
)
enable_testing()
add_test(TEST opendht_unit_tests)
......
......@@ -83,6 +83,8 @@ public:
DhtProxyServer& operator=(const DhtProxyServer& other) = delete;
DhtProxyServer& operator=(DhtProxyServer&& other) = delete;
asio::io_context& io_context() const;
struct ServerStats {
/** Current number of listen operations */
size_t listenCount;
......@@ -310,8 +312,6 @@ private:
void handlePrintStats(const asio::error_code &ec);
asio::io_context& io_context() const;
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;
......
......@@ -34,6 +34,7 @@
#include <memory>
#include <queue>
#include <json/json.h>
extern "C" {
struct http_parser;
......@@ -200,8 +201,11 @@ public:
using OnStatusCb = std::function<void(unsigned int status_code)>;
using OnDataCb = std::function<void(const char* at, size_t length)>;
using OnStateChangeCb = std::function<void(State state, const Response& response)>;
using OnJsonCb = std::function<void(Json::Value value, unsigned int status_code)>;
// resolves implicitly
Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger = {});
Request(asio::io_context& ctx, const std::string& host, const std::string& service,
const bool ssl = false, std::shared_ptr<dht::Logger> logger = {});
......
......@@ -401,11 +401,42 @@ Resolver::resolve(const std::string& host, const std::string& service)
unsigned int Request::ids_ = 1;
Request::Request(asio::io_context& ctx, const std::string& url, const Json::Value& json, OnJsonCb jsoncb,
std::shared_ptr<dht::Logger> logger)
: id_(Request::ids_++), ctx_(ctx), logger_(logger)
{
cbs_ = std::make_unique<Callbacks>();
resolver_ = std::make_shared<Resolver>(ctx, url, logger_);
set_header_field(restinio::http_field_t::host, get_url().host + ":" + get_url().service);
set_target(resolver_->get_url().target);
set_header_field(restinio::http_field_t::content_type, "application/json");
set_header_field(restinio::http_field_t::accept, "application/json");
Json::StreamWriterBuilder wbuilder;
set_body(Json::writeString(wbuilder, json));
add_on_state_change_callback([this, jsoncb](State state, const Response& response){
if (state != Request::State::DONE)
return;
Json::Value json;
std::string err;
Json::CharReaderBuilder rbuilder;
auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
if (!reader->parse(response.body.data(), response.body.data() + response.body.size(), &json, &err) and logger_)
logger_->e("[http:client] [request:%i] can't parse response to json", id_, err.c_str());
if (jsoncb)
jsoncb(json, response.status_code);
});
}
Request::Request(asio::io_context& ctx, const std::string& url, std::shared_ptr<dht::Logger> logger)
: id_(Request::ids_++), ctx_(ctx), logger_(logger)
{
cbs_ = std::make_unique<Callbacks>();
resolver_ = std::make_shared<Resolver>(ctx, url, logger_);
set_header_field(restinio::http_field_t::host, get_url().host + ":" + get_url().service);
set_target(resolver_->get_url().target);
}
......
if ENABLE_TESTS
bin_PROGRAMS = opendht_unit_tests
AM_CPPFLAGS = -I../include
AM_CPPFLAGS = -I../include -DOPENDHT_JSONCPP
nobase_include_HEADERS = infohashtester.h valuetester.h cryptotester.h dhtrunnertester.h httptester.h dhtproxytester.h
opendht_unit_tests_SOURCES = tests_runner.cpp cryptotester.cpp infohashtester.cpp valuetester.cpp dhtrunnertester.cpp httptester.cpp dhtproxytester.cpp
opendht_unit_tests_LDFLAGS = -lopendht -lcppunit -L@top_builddir@/src/.libs @GnuTLS_LIBS@
opendht_unit_tests_LDFLAGS = -lopendht -lcppunit -ljsoncpp -L@top_builddir@/src/.libs @GnuTLS_LIBS@
endif
g++ -Wall -Wextra -Wfatal-errors -pedantic -g ../src/http.cpp tests_runner.cpp httptester.cpp -o run.out -lopendht -lpthread -lcppunit -ljsoncpp -DOPENDHT_JSONCPP -I../include/opendht -DASIO_STANDALONE
......@@ -46,7 +46,7 @@ DhtProxyTester::setUp() {
serverProxy = std::unique_ptr<dht::DhtProxyServer>(
new dht::DhtProxyServer(
///*http*/nullptr,
///*http*/dht::crypto::Identity{},
/*https*/serverIdentity,
nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090", logger));
......
......@@ -33,10 +33,27 @@ CPPUNIT_TEST_SUITE_REGISTRATION(HttpTester);
void
HttpTester::setUp() {
logger = dht::log::getStdLogger();
nodePeer.run(0, /*identity*/{}, /*threaded*/true);
nodeProxy = std::make_shared<dht::DhtRunner>();
nodeProxy->run(0, /*identity*/{}, /*threaded*/true);
nodeProxy->bootstrap(nodePeer.getBound());
serverProxy = std::unique_ptr<dht::DhtProxyServer>(
new dht::DhtProxyServer(
/*http*/dht::crypto::Identity{}, nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090", logger));
}
void
HttpTester::tearDown() {
logger->d("[tester:http] stopping peer node");
nodePeer.join();
logger->d("[tester:http] stopping proxy server");
serverProxy.reset(nullptr);
logger->d("[tester:http] stopping proxy node");
nodeProxy->join();
}
void
......@@ -210,4 +227,38 @@ HttpTester::test_parse_url_target_ipv6() {
CPPUNIT_ASSERT(parsed.target == "/going/under");
}
void
HttpTester::test_send_json() {
// Arrange
std::condition_variable cv;
std::mutex cv_m;
std::unique_lock<std::mutex> lk(cv_m);
bool done = false;
dht::Value val {"hey"};
auto json = val.toJson();
json["permanent"] = false;
std::cout << "[test_send_json] sending:\n" << json << std::endl;
Json::Value resp_val;
unsigned int status = 0;
std::string url = "http://127.0.0.1:8080/key";
// Act
auto request = std::make_shared<dht::http::Request>(serverProxy->io_context(), url, json,
[this, &cv, &done, &status, &resp_val](Json::Value value, unsigned int status_code){
if (status_code != 200 and logger)
logger->e("[tester] [status] failed with code=%i", status_code);
std::cout << "[tester] got response:\n" << value << std::endl;
resp_val = value;
status = status_code;
done = true;
cv.notify_all();
}, logger);
request->set_method(restinio::http_method_post());
request->send();
// Assert
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(10), [&]{ return done; }));
CPPUNIT_ASSERT(status == 200);
CPPUNIT_ASSERT(resp_val["data"] == val.toJson()["data"]);
}
} // namespace test
......@@ -23,13 +23,18 @@
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <opendht/value.h>
#include <opendht/log.h>
#include <opendht/http.h>
#include <opendht/dhtrunner.h>
#include <opendht/dht_proxy_server.h>
namespace test {
class HttpTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(HttpTester);
// parse_url
CPPUNIT_TEST(test_parse_url);
CPPUNIT_TEST(test_parse_https_url_no_service);
CPPUNIT_TEST(test_parse_url_no_prefix_no_target);
......@@ -42,6 +47,8 @@ class HttpTester : public CppUnit::TestFixture {
CPPUNIT_TEST(test_parse_url_ipv6);
CPPUNIT_TEST(test_parse_url_no_prefix_no_target_ipv6);
CPPUNIT_TEST(test_parse_url_target_ipv6);
// send
CPPUNIT_TEST(test_send_json);
CPPUNIT_TEST_SUITE_END();
public:
......@@ -75,9 +82,17 @@ class HttpTester : public CppUnit::TestFixture {
void test_parse_url_ipv6();
void test_parse_url_no_prefix_no_target_ipv6();
void test_parse_url_target_ipv6();
/**
* Test send(json)
*/
void test_send_json();
private:
std::shared_ptr<dht::Logger> logger {};
dht::DhtRunner nodePeer;
std::shared_ptr<dht::DhtRunner> nodeProxy;
std::unique_ptr<dht::DhtProxyServer> serverProxy;
};
} // namespace test
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment