Initial attempt at parsing commit requests
This commit is contained in:
257
tests/test_commit_request.cpp
Normal file
257
tests/test_commit_request.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include "commit_request.hpp"
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
TEST_CASE("CommitRequest basic parsing") {
|
||||
CommitRequest request;
|
||||
|
||||
SUBCASE("Simple commit request") {
|
||||
std::string json = R"({
|
||||
"request_id": "test123",
|
||||
"leader_id": "leader456",
|
||||
"read_version": 12345
|
||||
})";
|
||||
|
||||
REQUIRE(request.parse_json(json));
|
||||
REQUIRE(request.request_id().has_value());
|
||||
REQUIRE(request.request_id().value() == "test123");
|
||||
REQUIRE(request.leader_id() == "leader456");
|
||||
REQUIRE(request.read_version() == 12345);
|
||||
}
|
||||
|
||||
SUBCASE("With preconditions") {
|
||||
std::string json = R"({
|
||||
"leader_id": "leader456",
|
||||
"read_version": 12345,
|
||||
"preconditions": [
|
||||
{
|
||||
"type": "point_read",
|
||||
"version": 12340,
|
||||
"key": "dGVzdA=="
|
||||
}
|
||||
]
|
||||
})";
|
||||
|
||||
REQUIRE(request.parse_json(json));
|
||||
REQUIRE(request.preconditions().size() == 1);
|
||||
REQUIRE(request.preconditions()[0].type == Precondition::Type::PointRead);
|
||||
REQUIRE(request.preconditions()[0].version.has_value());
|
||||
REQUIRE(request.preconditions()[0].version.value() == 12340);
|
||||
REQUIRE(request.preconditions()[0].key == "test"); // "dGVzdA==" decoded
|
||||
}
|
||||
|
||||
SUBCASE("With operations") {
|
||||
std::string json = R"({
|
||||
"leader_id": "leader456",
|
||||
"read_version": 12345,
|
||||
"operations": [
|
||||
{
|
||||
"type": "write",
|
||||
"key": "dGVzdA==",
|
||||
"value": "dmFsdWU="
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"key": "dGVzdDI="
|
||||
}
|
||||
]
|
||||
})";
|
||||
|
||||
REQUIRE(request.parse_json(json));
|
||||
REQUIRE(request.operations().size() == 2);
|
||||
|
||||
REQUIRE(request.operations()[0].type == Operation::Type::Write);
|
||||
REQUIRE(request.operations()[0].key == "test");
|
||||
REQUIRE(request.operations()[0].value.has_value());
|
||||
REQUIRE(request.operations()[0].value.value() == "value");
|
||||
|
||||
REQUIRE(request.operations()[1].type == Operation::Type::Delete);
|
||||
REQUIRE(request.operations()[1].key == "test2");
|
||||
}
|
||||
|
||||
SUBCASE("Invalid JSON") {
|
||||
std::string json = R"({
|
||||
"leader_id": "leader456",
|
||||
"read_version": "not_a_number"
|
||||
})";
|
||||
|
||||
REQUIRE_FALSE(request.parse_json(json));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CommitRequest memory management") {
|
||||
CommitRequest request;
|
||||
|
||||
std::string json = R"({
|
||||
"request_id": "test123",
|
||||
"leader_id": "leader456",
|
||||
"read_version": 12345,
|
||||
"operations": [
|
||||
{
|
||||
"type": "write",
|
||||
"key": "dGVzdA==",
|
||||
"value": "dmFsdWU="
|
||||
}
|
||||
]
|
||||
})";
|
||||
|
||||
REQUIRE(request.parse_json(json));
|
||||
|
||||
// Check that arena allocation worked
|
||||
REQUIRE(request.total_allocated() > 0);
|
||||
REQUIRE(request.used_bytes() > 0);
|
||||
|
||||
// Test reset
|
||||
request.reset();
|
||||
REQUIRE(request.request_id().has_value() == false);
|
||||
REQUIRE(request.leader_id().empty());
|
||||
REQUIRE(request.read_version() == 0);
|
||||
REQUIRE(request.operations().empty());
|
||||
}
|
||||
|
||||
TEST_CASE("CommitRequest streaming parsing") {
|
||||
CommitRequest request;
|
||||
|
||||
SUBCASE("Simple streaming parse") {
|
||||
std::string json = R"({
|
||||
"request_id": "test123",
|
||||
"leader_id": "leader456",
|
||||
"read_version": 12345
|
||||
})";
|
||||
|
||||
REQUIRE(request.begin_streaming_parse());
|
||||
|
||||
// Parse in small chunks to simulate network reception
|
||||
std::string mutable_json = json;
|
||||
size_t chunk_size = 10;
|
||||
size_t offset = 0;
|
||||
|
||||
CommitRequest::ParseStatus status = CommitRequest::ParseStatus::Incomplete;
|
||||
|
||||
while (offset < mutable_json.size() &&
|
||||
status == CommitRequest::ParseStatus::Incomplete) {
|
||||
size_t len = std::min(chunk_size, mutable_json.size() - offset);
|
||||
status = request.parse_chunk(mutable_json.data() + offset, len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (status == CommitRequest::ParseStatus::Incomplete) {
|
||||
status = request.finish_streaming_parse();
|
||||
}
|
||||
|
||||
REQUIRE(status == CommitRequest::ParseStatus::Complete);
|
||||
REQUIRE(request.is_parse_complete());
|
||||
REQUIRE_FALSE(request.has_parse_error());
|
||||
|
||||
REQUIRE(request.request_id().has_value());
|
||||
REQUIRE(request.request_id().value() == "test123");
|
||||
REQUIRE(request.leader_id() == "leader456");
|
||||
REQUIRE(request.read_version() == 12345);
|
||||
}
|
||||
|
||||
SUBCASE("Streaming parse with complex data") {
|
||||
std::string json = R"({
|
||||
"request_id": "streaming-test",
|
||||
"leader_id": "leader789",
|
||||
"read_version": 98765,
|
||||
"preconditions": [
|
||||
{
|
||||
"type": "point_read",
|
||||
"version": 98764,
|
||||
"key": "dGVzdEtleQ=="
|
||||
}
|
||||
],
|
||||
"operations": [
|
||||
{
|
||||
"type": "write",
|
||||
"key": "dGVzdEtleQ==",
|
||||
"value": "dGVzdFZhbHVl"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"key": "ZGVsZXRlS2V5"
|
||||
}
|
||||
]
|
||||
})";
|
||||
|
||||
REQUIRE(request.begin_streaming_parse());
|
||||
|
||||
// Parse one character at a time to really stress test streaming
|
||||
std::string mutable_json = json;
|
||||
CommitRequest::ParseStatus status = CommitRequest::ParseStatus::Incomplete;
|
||||
|
||||
for (size_t i = 0; i < mutable_json.size() &&
|
||||
status == CommitRequest::ParseStatus::Incomplete;
|
||||
++i) {
|
||||
status = request.parse_chunk(mutable_json.data() + i, 1);
|
||||
}
|
||||
|
||||
if (status == CommitRequest::ParseStatus::Incomplete) {
|
||||
status = request.finish_streaming_parse();
|
||||
}
|
||||
|
||||
REQUIRE(status == CommitRequest::ParseStatus::Complete);
|
||||
REQUIRE(request.is_parse_complete());
|
||||
|
||||
REQUIRE(request.request_id().value() == "streaming-test");
|
||||
REQUIRE(request.leader_id() == "leader789");
|
||||
REQUIRE(request.read_version() == 98765);
|
||||
REQUIRE(request.preconditions().size() == 1);
|
||||
REQUIRE(request.operations().size() == 2);
|
||||
|
||||
// Verify precondition was parsed correctly
|
||||
REQUIRE(request.preconditions()[0].type == Precondition::Type::PointRead);
|
||||
REQUIRE(request.preconditions()[0].version.value() == 98764);
|
||||
REQUIRE(request.preconditions()[0].key == "testKey");
|
||||
|
||||
// Verify operations were parsed correctly
|
||||
REQUIRE(request.operations()[0].type == Operation::Type::Write);
|
||||
REQUIRE(request.operations()[0].key == "testKey");
|
||||
REQUIRE(request.operations()[0].value.value() == "testValue");
|
||||
|
||||
REQUIRE(request.operations()[1].type == Operation::Type::Delete);
|
||||
REQUIRE(request.operations()[1].key == "deleteKey");
|
||||
}
|
||||
|
||||
SUBCASE("Streaming parse error handling") {
|
||||
std::string invalid_json = R"({
|
||||
"leader_id": "leader456",
|
||||
"read_version": "invalid_number"
|
||||
})";
|
||||
|
||||
REQUIRE(request.begin_streaming_parse());
|
||||
|
||||
std::string mutable_json = invalid_json;
|
||||
CommitRequest::ParseStatus status =
|
||||
request.parse_chunk(mutable_json.data(), mutable_json.size());
|
||||
|
||||
if (status == CommitRequest::ParseStatus::Incomplete) {
|
||||
status = request.finish_streaming_parse();
|
||||
}
|
||||
|
||||
REQUIRE(status == CommitRequest::ParseStatus::Error);
|
||||
REQUIRE(request.has_parse_error());
|
||||
REQUIRE_FALSE(request.is_parse_complete());
|
||||
}
|
||||
|
||||
SUBCASE("Complete document in single chunk") {
|
||||
std::string json = R"({"leader_id": "test", "read_version": 123})";
|
||||
|
||||
REQUIRE(request.begin_streaming_parse());
|
||||
|
||||
std::string mutable_json = json;
|
||||
CommitRequest::ParseStatus status =
|
||||
request.parse_chunk(mutable_json.data(), mutable_json.size());
|
||||
|
||||
// Should still be incomplete (streaming parser doesn't know if more data is
|
||||
// coming)
|
||||
REQUIRE(status == CommitRequest::ParseStatus::Incomplete);
|
||||
|
||||
// Signal end of input to complete parsing
|
||||
status = request.finish_streaming_parse();
|
||||
REQUIRE(status == CommitRequest::ParseStatus::Complete);
|
||||
REQUIRE(request.is_parse_complete());
|
||||
REQUIRE(request.leader_id() == "test");
|
||||
REQUIRE(request.read_version() == 123);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user