Files
backend/test/test_main.cc
T

207 lines
5.7 KiB
C++

#define DROGON_TEST_MAIN
#include <drogon/HttpClient.h>
#include <drogon/drogon.h>
#include <drogon/drogon_test.h>
#include "common/GeoJson.h"
#include "common/Crypto.h"
#include "common/Http.h"
#include "common/Validation.h"
#include "repositories/Sql.h"
#include <future>
using namespace drogon;
namespace
{
std::pair<ReqResult, HttpResponsePtr> sendRequest(const HttpRequestPtr &request)
{
auto client = HttpClient::newHttpClient("http://127.0.0.1:15555",
app().getLoop());
auto promise =
std::make_shared<std::promise<std::pair<ReqResult, HttpResponsePtr>>>();
auto future = promise->get_future();
client->sendRequest(
request,
[promise](ReqResult result, const HttpResponsePtr &response) {
promise->set_value({result, response});
});
return future.get();
}
} // namespace
DROGON_TEST(HealthEndpoint)
{
auto request = HttpRequest::newHttpRequest();
request->setMethod(Get);
request->setPath("/api/v1/health");
auto [result, response] = sendRequest(request);
REQUIRE(result == ReqResult::Ok);
REQUIRE(response != nullptr);
CHECK(response->getStatusCode() == k200OK);
REQUIRE(response->getJsonObject() != nullptr);
CHECK((*response->getJsonObject())["status"].asString() == "ok");
CHECK((*response->getJsonObject())["service"].asString() ==
"visione-backend");
}
DROGON_TEST(ValidationRejectsMalformedIdentity)
{
CHECK(visione::validation::isValidEmail("[email protected]"));
CHECK(!visione::validation::isValidEmail("not-an-email"));
CHECK(visione::validation::isValidFiscalCode("RSSMRA80A01H501U"));
CHECK(visione::validation::isValidFiscalCode("VSSGNR94M08A662P"));
CHECK(!visione::validation::isValidFiscalCode("short"));
CHECK(!visione::validation::isValidFiscalCode("VSSGNR94M08A662A"));
}
DROGON_TEST(SqlScalarSerializationKeepsTypes)
{
const auto json = []() {
Json::Value value(Json::objectValue);
value["id"] = Json::UInt64(7);
value["banned"] = false;
value["points"] = Json::Int64(42);
value["phone"] = "380 6180216";
return value;
}();
CHECK(json["id"].isUInt64());
CHECK(json["banned"].isBool());
CHECK(json["points"].isInt64());
CHECK(json["phone"].isString());
}
DROGON_TEST(CryptoHmacIsDeterministic)
{
const auto digest = visione::crypto::hmacSha256Hex("secret", "{\"a\":1}");
CHECK(digest == "AA9E2E3575F5D7098B6CACCD790888C36D5FDB63342A73BADA2D6A51747A8494");
CHECK(visione::crypto::constantTimeEquals(digest, digest));
CHECK(!visione::crypto::constantTimeEquals(digest, "different"));
}
DROGON_TEST(ParseJsonBodyRejectsInvalidPayload)
{
const auto parsed = visione::http::parseJsonBody("{\"ok\":true}");
CHECK(parsed.isObject());
CHECK(parsed["ok"].asBool());
const auto invalid = visione::http::parseJsonBody("{oops");
CHECK(invalid.isNull());
}
DROGON_TEST(GeoJsonMatchesPointInsidePolygon)
{
Json::Value polygon;
polygon["type"] = "Polygon";
Json::Value ring(Json::arrayValue);
Json::Value a(Json::arrayValue);
a.append(12.0);
a.append(41.0);
Json::Value b(Json::arrayValue);
b.append(13.0);
b.append(41.0);
Json::Value c(Json::arrayValue);
c.append(13.0);
c.append(42.0);
Json::Value d(Json::arrayValue);
d.append(12.0);
d.append(42.0);
ring.append(a);
ring.append(b);
ring.append(c);
ring.append(d);
ring.append(a);
polygon["coordinates"].append(ring);
CHECK(visione::geojson::pointInPolygon(41.5, 12.5, polygon));
CHECK(!visione::geojson::pointInPolygon(43.0, 12.5, polygon));
CHECK(visione::geojson::pointInGeometry(41.5, 12.5, polygon));
CHECK(!visione::geojson::pointInGeometry(43.0, 12.5, polygon));
}
DROGON_TEST(GeoJsonAcceptsContainedPolygon)
{
Json::Value container;
container["type"] = "Polygon";
Json::Value outer(Json::arrayValue);
Json::Value a(Json::arrayValue);
a.append(12.0);
a.append(41.0);
Json::Value b(Json::arrayValue);
b.append(13.0);
b.append(41.0);
Json::Value c(Json::arrayValue);
c.append(13.0);
c.append(42.0);
Json::Value d(Json::arrayValue);
d.append(12.0);
d.append(42.0);
outer.append(a);
outer.append(b);
outer.append(c);
outer.append(d);
outer.append(a);
container["coordinates"].append(outer);
Json::Value candidate;
candidate["type"] = "Polygon";
Json::Value inner(Json::arrayValue);
Json::Value p1(Json::arrayValue);
p1.append(12.2);
p1.append(41.2);
Json::Value p2(Json::arrayValue);
p2.append(12.8);
p2.append(41.2);
Json::Value p3(Json::arrayValue);
p3.append(12.8);
p3.append(41.8);
Json::Value p4(Json::arrayValue);
p4.append(12.2);
p4.append(41.8);
inner.append(p1);
inner.append(p2);
inner.append(p3);
inner.append(p4);
inner.append(p1);
candidate["coordinates"].append(inner);
CHECK(visione::geojson::polygonInsideGeometry(candidate, container));
candidate["coordinates"][0][3][0] = 14.0;
CHECK(!visione::geojson::polygonInsideGeometry(candidate, container));
}
int main(int argc, char **argv)
{
std::promise<void> startedPromise;
auto startedFuture = startedPromise.get_future();
app().addListener("127.0.0.1", 15555);
std::thread serverThread([&startedPromise]() {
app().getLoop()->queueInLoop([&startedPromise]() {
startedPromise.set_value();
});
app().run();
});
startedFuture.get();
const int status = test::run(argc, argv);
app().getLoop()->queueInLoop([]() {
app().quit();
});
serverThread.join();
return status;
}