Squashed commit of the following: commit 69d5ef7a256b86a86d46e5ae374c00fded1497ea Author: Ian Roddis <tech@kinesin.ca> Date: Thu Dec 16 12:15:55 2021 -0400 Updating readme commit 94a9f676d0f9cc0b55cdc18c4927eaea40d82c77 Author: Ian Roddis <tech@kinesin.ca> Date: Thu Dec 16 12:05:36 2021 -0400 Fixing serialization of attempt records when querying entire dag commit 945e5f90b24abf07c9af1bc4c6bbcb33e93b8069 Author: Ian Roddis <tech@kinesin.ca> Date: Thu Dec 16 11:37:59 2021 -0400 Compiles cleanly... commit 8b23e46081d47fb80dc1a2d998fc6dc4bbf301a8 Author: Ian Roddis <tech@kinesin.ca> Date: Thu Dec 16 10:43:03 2021 -0400 Adding in missing source file to cmake build list commit 6d10d9791206e2bc15788beadeea580b8e43a853 Author: Ian Roddis <tech@kinesin.ca> Date: Thu Dec 16 10:41:43 2021 -0400 Adding new executors commit 42a2c67f4d6ae99df95d917c8621d78cd99837a1 Author: Ian Roddis <tech@kinesin.ca> Date: Thu Dec 16 10:27:14 2021 -0400 Fixing missing curl cmake dependency commit 394bc4c5d51ecee7bf14712f719c8bf7e97fb0fa Author: Ian Roddis <tech@kinesin.ca> Date: Thu Dec 16 10:21:58 2021 -0400 Fixing missing curl cmake dependency commit dd9efc8e7e7770ea1bcbccb70a1af9cfcff0414c Author: Ian Roddis <tech@kinesin.ca> Date: Wed Dec 15 17:15:38 2021 -0400 Checkpointing progress commit 3b3b55d6037bb96e46de6763f486f4ecb92fe6a0 Author: Ian Roddis <tech@kinesin.ca> Date: Wed Dec 15 14:21:18 2021 -0400 updating readme commit 303027c11452941b2a0c0d1b04ac5942e79efd74 Author: Ian Roddis <tech@kinesin.ca> Date: Wed Dec 15 14:17:16 2021 -0400 Namespacing daggyd Adding more error checking around deserialization of parameters Adding tests for runner agent commit c592eaeba12e2a449bae401e8c1d9ed236416d52 Author: Ian Roddis <tech@kinesin.ca> Date: Wed Dec 15 11:20:21 2021 -0400 Checkpointing work commit fb1862d1cefe2b53a98659cce3c8c73d88bf5d84 Author: Ian Roddis <tech@kinesin.ca> Date: Wed Dec 15 09:52:29 2021 -0400 Copying daggyd for daggyr template, adding in basic routes
173 lines
4.8 KiB
C++
173 lines
4.8 KiB
C++
#include <curl/curl.h>
|
|
#include <rapidjson/document.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <catch2/catch.hpp>
|
|
#include <daggy/Serialization.hpp>
|
|
#include <daggy/executors/task/ForkingTaskExecutor.hpp>
|
|
#include <daggy/executors/task/NoopTaskExecutor.hpp>
|
|
#include <daggy/loggers/dag_run/OStreamLogger.hpp>
|
|
#include <daggyr/Server.hpp>
|
|
#include <filesystem>
|
|
#include <iostream>
|
|
#include <thread>
|
|
|
|
namespace rj = rapidjson;
|
|
|
|
using namespace daggy;
|
|
|
|
TEST_CASE("rest_endpoint", "[server_basic]")
|
|
{
|
|
std::stringstream ss;
|
|
Pistache::Address listenSpec("localhost", Pistache::Port(0));
|
|
|
|
const ssize_t maxCores = 10, maxMemoryMB = 1000;
|
|
|
|
daggyr::Server server(listenSpec, maxCores, maxMemoryMB);
|
|
server.init(10);
|
|
server.start();
|
|
|
|
const std::string host = "localhost:";
|
|
const std::string baseURL = host + std::to_string(server.getPort());
|
|
|
|
SECTION("Ready Endpoint")
|
|
{
|
|
auto response = HTTP_REQUEST(baseURL + "/ready");
|
|
REQUIRE(response.code == HTTPCode::Ok);
|
|
}
|
|
|
|
SECTION("Querying a non-existent task should yield a 404")
|
|
{
|
|
auto response = HTTP_REQUEST(baseURL + "/v1/task/100/sample_name");
|
|
REQUIRE(response.code == HTTPCode::Not_Found);
|
|
}
|
|
|
|
SECTION("Task Missing Cores should Fail")
|
|
{
|
|
std::string taskSpec =
|
|
R"({ "job": { "command": [ "/usr/bin/touch", "dagrun_{{FILE}}" ]}, "memoryMB": 100 })";
|
|
|
|
auto response =
|
|
HTTP_REQUEST(baseURL + "/v1/task/0/sample_task", taskSpec, "POST");
|
|
REQUIRE(response.code == HTTPCode::Not_Acceptable);
|
|
}
|
|
|
|
SECTION("Task Missing MemoryMB should Fail")
|
|
{
|
|
std::string taskSpec =
|
|
R"({ "job": { "command": [ "/usr/bin/touch", "dagrun_{{FILE}}" ]}, "cores": 100 })";
|
|
|
|
auto response =
|
|
HTTP_REQUEST(baseURL + "/v1/task/0/sample_task", taskSpec, "POST");
|
|
REQUIRE(response.code == HTTPCode::Not_Acceptable);
|
|
}
|
|
|
|
SECTION("Task submission and get result")
|
|
{
|
|
std::string taskSpec =
|
|
R"({ "job": { "command": [ "/usr/bin/echo", "hello", "world" ], "cores": "1", "memoryMB": "100" } })";
|
|
|
|
// Submit
|
|
{
|
|
auto response =
|
|
HTTP_REQUEST(baseURL + "/v1/task/0/sample_task", taskSpec, "POST");
|
|
REQUIRE(response.code == HTTPCode::Ok);
|
|
}
|
|
|
|
while (true) {
|
|
auto [code, doc] = JSON_HTTP_REQUEST(baseURL + "/v1/task/0/sample_task");
|
|
REQUIRE(doc.IsObject());
|
|
REQUIRE(doc.HasMember("state"));
|
|
|
|
std::string state = doc["state"].GetString();
|
|
if (state != "COMPLETED") {
|
|
std::this_thread::sleep_for(250ms);
|
|
}
|
|
else {
|
|
REQUIRE(doc.HasMember("attempt"));
|
|
auto attempt = attemptRecordFromJSON(doc["attempt"]);
|
|
|
|
REQUIRE(attempt.rc == 0);
|
|
REQUIRE(attempt.outputLog == "hello world\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("Task capacity changes")
|
|
{
|
|
std::string taskSpec =
|
|
R"({ "job": { "command": [ "/usr/bin/sleep", "5" ], "cores": "1", "memoryMB": "100" } })";
|
|
|
|
auto getCapacity = [&]() -> daggy::executors::task::daggy_runner::Capacity {
|
|
daggy::executors::task::daggy_runner::Capacity cap;
|
|
auto [code, doc] = JSON_HTTP_REQUEST(baseURL + "/v1/capacity");
|
|
REQUIRE(doc.IsObject());
|
|
REQUIRE(doc.HasMember("current"));
|
|
const auto &cur = doc["current"];
|
|
REQUIRE(cur.IsObject());
|
|
REQUIRE(cur.HasMember("cores"));
|
|
REQUIRE(cur.HasMember("memoryMB"));
|
|
|
|
cap.cores = cur["cores"].GetInt64();
|
|
cap.memoryMB = cur["memoryMB"].GetInt64();
|
|
|
|
return cap;
|
|
};
|
|
|
|
auto preCap = getCapacity();
|
|
|
|
// Submit
|
|
{
|
|
auto response =
|
|
HTTP_REQUEST(baseURL + "/v1/task/0/sample_task", taskSpec, "POST");
|
|
REQUIRE(response.code == HTTPCode::Ok);
|
|
}
|
|
|
|
auto postCap = getCapacity();
|
|
|
|
REQUIRE(postCap.cores == preCap.cores - 1);
|
|
REQUIRE(postCap.memoryMB == preCap.memoryMB - 100);
|
|
|
|
// Ensure the current job is running
|
|
{
|
|
auto [code, doc] = JSON_HTTP_REQUEST(baseURL + "/v1/task/0/sample_task");
|
|
REQUIRE(doc.IsObject());
|
|
REQUIRE(doc.HasMember("state"));
|
|
REQUIRE(doc["state"] != "COMPLETED");
|
|
}
|
|
|
|
// Stop it
|
|
{
|
|
auto [code, doc] =
|
|
JSON_HTTP_REQUEST(baseURL + "/v1/task/0/sample_task", "", "DELETE");
|
|
REQUIRE(code == HTTPCode::Ok);
|
|
}
|
|
|
|
// Grab it and ensure it was killed
|
|
while (true) {
|
|
auto response = HTTP_REQUEST(baseURL + "/v1/task/0/sample_task");
|
|
|
|
REQUIRE(response.code == HTTPCode::Ok);
|
|
rj::Document doc;
|
|
daggy::checkRJParse(doc.Parse(response.body.c_str()));
|
|
REQUIRE(doc.IsObject());
|
|
REQUIRE(doc.HasMember("state"));
|
|
|
|
std::string state = doc["state"].GetString();
|
|
if (state != "COMPLETED") {
|
|
std::this_thread::sleep_for(250ms);
|
|
}
|
|
else {
|
|
REQUIRE(doc.HasMember("attempt"));
|
|
auto attempt = attemptRecordFromJSON(doc["attempt"]);
|
|
|
|
REQUIRE(attempt.rc != 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
server.shutdown();
|
|
}
|