Skip to content
Permalink
Browse files

http: add send json & unit test

  • Loading branch information...
binarytrails authored and aberaud committed Sep 23, 2019
1 parent 6f87e9d commit d0510dcb722e0476e8b345610e1b376dba2448e5
@@ -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 @@ class OPENDHT_PUBLIC DhtProxyServer
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 @@ class OPENDHT_PUBLIC DhtProxyServer

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 @@ class OPENDHT_PUBLIC Request
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);
}

@@ -1,9 +1,9 @@
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
@@ -0,0 +1 @@
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 comments on commit d0510dc

Please sign in to comment.
You can’t perform that action at this time.