diff --git a/toREST/CMakeLists.txt b/toREST/CMakeLists.txt index 80169b2..84e0cc3 100644 --- a/toREST/CMakeLists.txt +++ b/toREST/CMakeLists.txt @@ -33,12 +33,12 @@ set(global_libraries add_library(project_shared OBJECT ${source_files}) -add_executable(${project_name} ./src/main.cxx $) -target_link_libraries(${project_name} ${global_libraries}) +# add_executable(${project_name} ./src/main.cxx $) +# target_link_libraries(${project_name} ${global_libraries}) -# enable_testing() +enable_testing() -# file(GLOB test_files "./tests/*.cpp") +file(GLOB test_files "./tests/*.cpp") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -Wall -fprofile-arcs -ftest-coverage ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -Wall -fprofile-arcs -ftest-coverage ") @@ -46,10 +46,10 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage ") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage ") set(test test${project_name}) -# add_executable(${test} ${test_files} $) -#target_include_directories(${test} PUBLIC ../lib/Catch) -#target_link_libraries(${test} ${global_libraries}) -#add_test(${test} ${test}) +add_executable(${test} ${test_files} $) +target_include_directories(${test} PUBLIC ../lib/Catch) +target_link_libraries(${test} ${global_libraries}) +add_test(${test} ${test}) find_package(Doxygen) diff --git a/toREST/src/main.cxx b/toREST/src/main.cxx index 6c0c27e..399a967 100644 --- a/toREST/src/main.cxx +++ b/toREST/src/main.cxx @@ -2,6 +2,7 @@ #include #include #include +#include #include typedef SimpleWeb::Server HttpServer; @@ -57,42 +58,65 @@ int main(int argc, char *argv[]) { auto response_code = http::code(http::service_unavailable); response.set_body({{response_code.first, response_code.second}}); response.set_status(response_code.first); - return; - } - const auto json=util::json::parse(req->content); - if(json.is_object() && !json.is_null()) { - if(util::json::get("paused",json,session.is_paused())) - session.pause(); - else - session.resume(); - auto settings = session.get_settings(); - const auto new_listen_port=util::json::get("port",json,session.listen_port()); - if(new_listen_port!=session.listen_port()) - settings.set_str(settings.listen_interfaces,"0.0.0.0:"+std::to_string(new_listen_port)); - const auto new_dht_enabled=util::json::get("dht_enabled",json,session.is_dht_running()); - if(new_dht_enabled!=session.is_dht_running()) - settings.set_bool(settings.enable_dht,new_dht_enabled); - auto old_limit=settings.get_int(settings.download_rate_limit); - auto new_limit=util::json::get("down_limit",json,old_limit); - if(new_limit!=old_limit) - settings.set_int(settings.download_rate_limit,new_limit); - old_limit=settings.get_int(settings.upload_rate_limit); - new_limit=util::json::get("up_limit",json,old_limit); - if(new_limit!=old_limit) - settings.set_int(settings.upload_rate_limit,new_limit); - session.apply_settings(settings); - } else { - auto response_code = http::code(http::bad_request); - response.set_body({{response_code.first,response_code.second}}); - response.set_status(response_code.first); + } else { + const auto json=util::json::parse(req->content); + if(json.is_object() && !json.is_null()) { + if(util::json::get("paused",json,session.is_paused())) + session.pause(); + else + session.resume(); + auto settings = session.get_settings(); + const auto new_listen_port=util::json::get("port",json,session.listen_port()); + if(new_listen_port!=session.listen_port()) + settings.set_str(settings.listen_interfaces,"0.0.0.0:"+std::to_string(new_listen_port)); + const auto new_dht_enabled=util::json::get("dht_enabled",json,session.is_dht_running()); + if(new_dht_enabled!=session.is_dht_running()) + settings.set_bool(settings.enable_dht,new_dht_enabled); + auto old_limit=settings.get_int(settings.download_rate_limit); + auto new_limit=util::json::get("down_limit",json,old_limit); + if(new_limit!=old_limit) + settings.set_int(settings.download_rate_limit,new_limit); + old_limit=settings.get_int(settings.upload_rate_limit); + new_limit=util::json::get("up_limit",json,old_limit); + if(new_limit!=old_limit) + settings.set_int(settings.upload_rate_limit,new_limit); + session.apply_settings(settings); + response.set_body({{200,"OK"}}); + } else { + auto response_code = http::code(http::bad_request); + response.set_body({{response_code.first,response_code.second}}); + response.set_status(response_code.first); + } } *resp << response; }; http_server.resource["^/session/torrents(\\?.*)?\\/?$"]["GET"]=[&session](std::shared_ptr resp, std::shared_ptr req) { auto response = http::response(); - if (session.is_valid()) { - response.set_body(nlohmann::json::object({{"torrents",nlohmann::json::array()}})); + if(session.is_valid()) { + auto torrents = session.get_torrents(); + auto response_object = nlohmann::json::object(); + auto torrents_json = nlohmann::json::array(); + for(auto &torrent:torrents){ + if(torrent.is_valid()){ + const auto hash=torrent.info_hash().to_string(); + const auto status=torrent.status( + libtorrent::torrent_handle::query_name | + libtorrent::torrent_handle::query_save_path + ); + torrents_json.push_back({ + { "hash", hash }, + { "paused", status.paused }, + { "seeding", status.is_seeding }, + { "state", status.state }, + { "priority", status.priority }, + { "name",status.name } + }); + } + } + response_object["torrents"] = torrents_json; + response.set_status(http::ok); + response.set_body(response_object); } else { auto response_code = http::code(http::service_unavailable); response.set_body({{response_code.first, response_code.second}}); diff --git a/toREST/tests/http_test.cpp b/toREST/tests/http_test.cpp index ec38eb1..08f1b6c 100644 --- a/toREST/tests/http_test.cpp +++ b/toREST/tests/http_test.cpp @@ -32,33 +32,30 @@ SCENARIO("http response"){ REQUIRE(ss.str()=="HTTP/1.1 204 No Content\r\n\r\n"s); } GIVEN("we stream our response with the body set"){ - response.set_body("Easter eggs, everywhere! ye"); + response.set_body("Easter eggs, everywhere! ye"s); ss << response; THEN("our response contains the appropriate headers") REQUIRE(ss.str()=="HTTP/1.1 200 OK\r\nContent-Length: 103\r\n\r\nEaster eggs, everywhere! ye"s); } + GIVEN("we add a header to the resource"){ + response.set_body("Nothing"s); + response.add_header(http::header("Strict-Error"s,"on"s)); + ss << response; + THEN("our response contains the appropriate headers") + REQUIRE(ss.str()=="HTTP/1.1 200 OK\r\nStrict-Error: on\r\nContent-Length: 7\r\n\r\nNothing"s); + } } SCENARIO("Stream http responses with a json response"){ - auto response=http::json_response(); + auto response=http::response(); std::stringstream ss; - GIVEN("we stream our response without setting any options"){ - ss << response; - THEN("our response is valid json and the response code is 200") - REQUIRE(ss.str()=="HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 26\r\n\r\n{\"code\":200,\"status\":\"OK\"}"s); - } GIVEN("we set the response code to 404 and stream our response"){ response.set_status(http::not_found); + response.set_body({{"code",404},{"status","Not Found"}}); ss << response; THEN("our response is valid json and the resoinse code is 404") REQUIRE(ss.str()=="HTTP/1.1 404 Not Found\r\nContent-Type: application/json\r\nContent-Length: 33\r\n\r\n{\"code\":404,\"status\":\"Not Found\"}"s); } - GIVEN("we stream our response with the status set to 204 No Content"){ - response.set_status(http::no_content); - ss << response; - THEN("the response has no content header set") - REQUIRE(ss.str()=="HTTP/1.1 204 No Content\r\nContent-Type: application/json\r\n\r\n"s); - } GIVEN("we stream our response with the body set"){ response.set_body(nlohmann::json::object()); ss << response; diff --git a/toREST/tests/session_test.cpp b/toREST/tests/session_test.cpp deleted file mode 100644 index 20e3f4f..0000000 --- a/toREST/tests/session_test.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include - -using namespace fakeit; - -const std::string method_not_allowed_json ="HTTP/1.1 405 Method Not Allowed\r\nContent-Type: application/json\r\nContent-Length: 42\r\n\r\n{\"code\":405,\"status\":\"Method Not Allowed\"}"; -const std::string service_unavailable_json="HTTP/1.1 503 Service Unavailable\r\nContent-Type: application/json\r\nContent-Length: 43\r\n\r\n{\"code\":503,\"status\":\"Service Unavailable\"}"; -const std::string internal_server_error_json="HTTP/1.1 500 Internal Server Error\r\nContent-Type: application/json\r\nContent-Length: 45\r\n\r\n{\"code\":500,\"status\":\"Internal Server Error\"}"; -const std::string not_found ="HTTP/1.1 404 Not Found\r\nContent-Type: application/json\r\nContent-Length: 36\r\n\r\n{\"code\":404,\"status\":\"Not Found\"}"; -const std::string ok_nullptr_json ="HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 4\r\n\r\nnull"; -const std::string bad_request ="HTTP/1.1 400 Bad Request\r\nContent-Type: application/json\r\nContent-Length: 35\r\n\r\n{\"code\":400,\"status\":\"Bad Request\"}"; - -using namespace session; - -SCENARIO("test of responses by session_manager on /v1/session"){ - session::resource sut; - std::stringstream ss; - GIVEN("the session is invalid"){ - WHEN("we receive a GET request"){ - sut.get(); - ss << sut; - THEN("the response is a 503 Service Unavailable JSON object") - REQUIRE(ss.str()==service_unavailable_json); - } - WHEN("we receive a PATCH request"){ - sut.patch(); - ss << sut; - THEN("the response is a 503 Service Unavailable JSON object") - REQUIRE(ss.str()==service_unavailable_json); - } - WHEN("we receive a POST request"){ - sut.post(); - ss << sut; - THEN("the response is a 405 Method Not Allowed JSON object") - REQUIRE(ss.str()==method_not_allowed_json); - } - WHEN("we receive a DELETE request"){ - sut.del(); - ss << sut; - THEN("the response is a 405 Method Not Allowed JSON object") - REQUIRE(ss.str()==method_not_allowed_json); - } - WHEN("we receive a PUT request"){ - sut.put(); - ss << sut; - THEN("the response is a 405 Method Not Allowed JSON object") - REQUIRE(ss.str()==method_not_allowed_json); - } - } - GIVEN("the session is valid"){ - Mock mock_session; - When(Method(mock_session,basic_manager::is_valid)).AlwaysReturn(true); - When(Method(mock_session,basic_manager::get_json)).AlwaysReturn(nullptr); - auto session=std::shared_ptr(&(mock_session.get()),[](...){}); - sut.set_session(session); - - WHEN("we receive a GET request"){ - sut.get(); - ss << sut; - THEN("the response is a 200 OK JSON object ") - REQUIRE(ss.str()==ok_nullptr_json); - } - - WHEN("we receive a PATCH request with invalid data"){ - GIVEN("the JSON is invalid"){ - sut.patch(nullptr); - ss << sut; - THEN("the response is a 400 Bad Request JSON object") - REQUIRE(ss.str()==bad_request); - } - GIVEN("the JSON is valid, but contains no data"){ - sut.patch({}); - ss << sut; - THEN("the response is a 400 Bad Request JSON object") - REQUIRE(ss.str()==bad_request); - } - GIVEN("the JSON is valid, but the port number is to low"){ - When(Method(mock_session,basic_manager::patch)).AlwaysReturn(false); - sut.patch({{"listen_port",1}}); - ss << sut; - THEN("the response is a 500 Internal Server Error JSON object") - REQUIRE(ss.str()==internal_server_error_json); - } - GIVEN("the JSON is valid, but listen_port is a string"){ - sut.patch({{"listen_port","1"}}); - ss << sut; - THEN("the response is a 400 Bad Request JSON object") - REQUIRE(ss.str()==bad_request); - } - GIVEN("the JSON is valid, but is_paused is a string"){ - sut.patch({{"is_paused","1"}}); - ss << sut; - THEN("the response is a 400 Bad Request JSON object") - REQUIRE(ss.str()==bad_request); - } - WHEN("we receive a POST request"){ - sut.post(); - ss << sut; - THEN("the response is a 405 Method Not Allowed JSON object") - REQUIRE(ss.str()==method_not_allowed_json); - } - WHEN("we receive a DELETE request"){ - sut.del(); - ss << sut; - THEN("the response is a 405 Method Not Allowed JSON object") - REQUIRE(ss.str()==method_not_allowed_json); - } - WHEN("we receive a PUT request"){ - sut.put(); - ss << sut; - THEN("the response is a 405 Method Not Allowed JSON object") - REQUIRE(ss.str()==method_not_allowed_json); - } - } - } -} \ No newline at end of file