Files
weaseldb/tests/test_commit_request.cpp

481 lines
14 KiB
C++

#include "../benchmarks/test_data.hpp"
#include "parser_comparison.hpp"
#include <doctest/doctest.h>
/**
* @brief Test helper that uses parser comparison to validate both parsers.
*
* This function tests that either both parsers reject the input, or both
* accept it and produce equivalent CommitRequest objects.
*/
void test_parser_comparison(const std::string &json_str,
const std::string &test_name) {
INFO("Testing: " << test_name);
INFO("JSON: " << json_str);
auto result = ParserComparison::compare_parsers(json_str);
INFO("Comparison result: " << ParserComparison::result_to_string(result));
if (!ParserComparison::get_last_error().empty()) {
INFO("Error details: " << ParserComparison::get_last_error());
}
// Accept either both success or both failure - reject inconsistencies
REQUIRE((result == ParserComparison::ComparisonResult::BothSuccess ||
result == ParserComparison::ComparisonResult::BothFailure));
}
TEST_CASE("Parser Comparison - Basic Cases") {
SUBCASE("Simple valid request") {
test_parser_comparison(R"({
"request_id": "test123",
"leader_id": "leader456",
"read_version": 12345
})",
"Simple valid request");
}
SUBCASE("Minimal valid request (no request_id)") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345
})",
"Minimal valid request");
}
SUBCASE("Request with preconditions") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"preconditions": [
{
"type": "point_read",
"version": 12340,
"key": "dGVzdA=="
}
]
})",
"Request with preconditions");
}
SUBCASE("Request with operations") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"operations": [
{
"type": "write",
"key": "dGVzdA==",
"value": "dmFsdWU="
},
{
"type": "delete",
"key": "dGVzdDI="
}
]
})",
"Request with operations");
}
SUBCASE("Complex request with both preconditions and operations") {
test_parser_comparison(R"({
"request_id": "complex-test",
"leader_id": "leader789",
"read_version": 98765,
"preconditions": [
{
"type": "point_read",
"version": 98764,
"key": "dGVzdEtleQ=="
},
{
"type": "range_read",
"begin": "c3RhcnQ=",
"end": "ZW5k"
}
],
"operations": [
{
"type": "write",
"key": "dGVzdEtleQ==",
"value": "dGVzdFZhbHVl"
},
{
"type": "delete",
"key": "ZGVsZXRlS2V5"
},
{
"type": "range_delete",
"begin": "cmFuZ2VTdGFydA==",
"end": "cmFuZ2VFbmQ="
}
]
})",
"Complex request");
}
}
TEST_CASE("Parser Comparison - Invalid Cases") {
SUBCASE("Invalid JSON syntax") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": "not_a_number"
})",
"Invalid JSON - string for number");
}
SUBCASE("Missing required leader_id") {
test_parser_comparison(R"({
"request_id": "test123",
"read_version": 12345
})",
"Missing leader_id");
}
SUBCASE("Missing required read_version") {
test_parser_comparison(R"({
"request_id": "test123",
"leader_id": "leader456"
})",
"Missing read_version");
}
SUBCASE("Empty leader_id") {
test_parser_comparison(R"({
"request_id": "test123",
"leader_id": "",
"read_version": 12345
})",
"Empty leader_id");
}
SUBCASE("Invalid precondition - missing key") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"preconditions": [
{
"type": "point_read"
}
]
})",
"Invalid precondition - missing key");
}
SUBCASE("Invalid precondition - missing begin for range_read") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"preconditions": [
{
"type": "range_read",
"end": "dGVzdFo="
}
]
})",
"Invalid precondition - missing begin");
}
SUBCASE("Invalid precondition - missing end for range_read") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"preconditions": [
{
"type": "range_read",
"begin": "dGVzdA=="
}
]
})",
"Invalid precondition - missing end");
}
SUBCASE("Invalid operation - missing key for write") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"operations": [
{
"type": "write",
"value": "dmFsdWU="
}
]
})",
"Invalid operation - missing key");
}
SUBCASE("Invalid operation - missing value for write") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"operations": [
{
"type": "write",
"key": "dGVzdA=="
}
]
})",
"Invalid operation - missing value");
}
SUBCASE("Invalid operation - missing key for delete") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"operations": [
{
"type": "delete"
}
]
})",
"Invalid operation - missing key for delete");
}
SUBCASE("Invalid operation - missing begin for range_delete") {
test_parser_comparison(
R"({
"leader_id": "leader456",
"read_version": 12345,
"operations": [
{
"type": "range_delete",
"end": "dGVzdFo="
}
]
})",
"Invalid operation - missing begin for range_delete");
}
SUBCASE("Invalid operation - missing end for range_delete") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"operations": [
{
"type": "range_delete",
"begin": "dGVzdA=="
}
]
})",
"Invalid operation - missing end for range_delete");
}
SUBCASE("Malformed JSON") {
test_parser_comparison(R"({
"leader_id": "leader456"
"read_version": 12345
})",
"Malformed JSON - missing comma");
}
SUBCASE("Invalid precondition type") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"preconditions": [
{
"type": "invalid_type",
"key": "dGVzdA=="
}
]
})",
"Invalid precondition type");
}
SUBCASE("Invalid operation type") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"operations": [
{
"type": "invalid_operation",
"key": "dGVzdA=="
}
]
})",
"Invalid operation type");
}
}
TEST_CASE("Parser Comparison - Edge Cases") {
SUBCASE("Empty arrays") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"preconditions": [],
"operations": []
})",
"Empty arrays");
}
SUBCASE("Empty base64 strings") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"operations": [
{
"type": "write",
"key": "",
"value": ""
}
]
})",
"Empty base64 strings");
}
SUBCASE("Zero read_version") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 0
})",
"Zero read_version");
}
SUBCASE("Large read_version") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 9223372036854775807
})",
"Large read_version");
}
SUBCASE("Precondition with zero version") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"preconditions": [
{
"type": "point_read",
"version": 0,
"key": "dGVzdA=="
}
]
})",
"Precondition with zero version");
}
SUBCASE("Range operations with empty keys") {
test_parser_comparison(R"({
"leader_id": "leader456",
"read_version": 12345,
"preconditions": [
{
"type": "range_read",
"begin": "",
"end": ""
}
],
"operations": [
{
"type": "range_delete",
"begin": "",
"end": ""
}
]
})",
"Range operations with empty keys");
}
}
TEST_CASE("Parser Comparison - Test Data") {
SUBCASE("SIMPLE_JSON") {
test_parser_comparison(weaseldb::test_data::SIMPLE_JSON,
"SIMPLE_JSON test data");
}
SUBCASE("MEDIUM_JSON") {
test_parser_comparison(weaseldb::test_data::MEDIUM_JSON,
"MEDIUM_JSON test data");
}
SUBCASE("COMPLEX_JSON") {
test_parser_comparison(weaseldb::test_data::COMPLEX_JSON,
"COMPLEX_JSON test data");
}
SUBCASE("Generated large JSON") {
// Test with a reasonably sized generated JSON to avoid extremely long test
// times
std::string large_json = weaseldb::test_data::generate_large_json(100);
test_parser_comparison(large_json, "Generated large JSON (100 operations)");
}
}
TEST_CASE("Parser Comparison - Stress Tests") {
SUBCASE("Multiple operations of each type") {
test_parser_comparison(R"({
"request_id": "stress-test-operations",
"leader_id": "stress-leader",
"read_version": 1000000,
"operations": [
{
"type": "write",
"key": "a2V5MQ==",
"value": "dmFsdWUx"
},
{
"type": "write",
"key": "a2V5Mg==",
"value": "dmFsdWUy"
},
{
"type": "delete",
"key": "a2V5Mw=="
},
{
"type": "delete",
"key": "a2V5NA=="
},
{
"type": "range_delete",
"begin": "cmFuZ2UxX3N0YXJ0",
"end": "cmFuZ2UxX2VuZA=="
},
{
"type": "range_delete",
"begin": "cmFuZ2UyX3N0YXJ0",
"end": "cmFuZ2UyX2VuZA=="
}
]
})",
"Multiple operations of each type");
}
SUBCASE("Multiple preconditions of each type") {
test_parser_comparison(R"({
"leader_id": "stress-leader",
"read_version": 2000000,
"preconditions": [
{
"type": "point_read",
"version": 1999999,
"key": "cG9pbnQx"
},
{
"type": "point_read",
"version": 1999998,
"key": "cG9pbnQy"
},
{
"type": "range_read",
"version": 1999997,
"begin": "cmFuZ2UxX3N0YXJ0",
"end": "cmFuZ2UxX2VuZA=="
},
{
"type": "range_read",
"begin": "cmFuZ2UyX3N0YXJ0",
"end": "cmFuZ2UyX2VuZA=="
}
]
})",
"Multiple preconditions of each type");
}
SUBCASE("Deep nesting with many operations") {
// Use the generate_large_json function which now properly encodes base64
std::string stress_json = weaseldb::test_data::generate_large_json(50);
test_parser_comparison(stress_json, "Deep nesting with many operations");
}
}