diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.cpp b/components/core/src/clp/ffi/ir_stream/Serializer.cpp index 0c4bcc7de..24d162573 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.cpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.cpp @@ -259,13 +259,14 @@ auto Serializer::change_utc_offset(UtcOffset utc_offset) -> } template -auto Serializer::serialize_log_event(msgpack::object const& log_event) -> bool { - if (msgpack::type::MAP != log_event.type) { +auto Serializer::serialize_msgpack_map(msgpack::object const& msgpack_map +) -> bool { + if (msgpack::type::MAP != msgpack_map.type) { return false; } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) - auto const& map{log_event.via.map}; + auto const& map{msgpack_map.via.map}; if (0 == map.size) { serialize_empty_object(m_ir_buf); return true; @@ -468,11 +469,11 @@ template auto Serializer::change_utc_offset(UtcOf ) -> void; template auto Serializer::change_utc_offset(UtcOffset utc_offset ) -> void; -template auto Serializer::serialize_log_event( - msgpack::object const& log_event +template auto Serializer::serialize_msgpack_map( + msgpack::object const& msgpack_map ) -> bool; -template auto Serializer::serialize_log_event( - msgpack::object const& log_event +template auto Serializer::serialize_msgpack_map( + msgpack::object const& msgpack_map ) -> bool; template auto Serializer::serialize_schema_tree_node( SchemaTree::NodeLocator const& locator diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.hpp b/components/core/src/clp/ffi/ir_stream/Serializer.hpp index c76c2dcbf..6b2d41139 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.hpp @@ -82,11 +82,11 @@ class Serializer { auto change_utc_offset(UtcOffset utc_offset) -> void; /** - * Serializes the given log event. - * @param log_event Key-value pair log event to serialize, represented as a msgpack object. + * Serializes the given msgpack map as a key-value pair log event. + * @param msgpack_map msgpack key-value pair map to serialize, representing an log event. * @return Whether the serialization succeeded. */ - [[nodiscard]] auto serialize_log_event(msgpack::object const& log_event) -> bool; + [[nodiscard]] auto serialize_msgpack_map(msgpack::object const& msgpack_map) -> bool; private: // Constructors diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index 167803e58..4ee92866f 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -1,9 +1,12 @@ #include +#include +#include #include #include #include #include +#include #include "../src/clp/BufferReader.hpp" #include "../src/clp/ErrorCode.hpp" @@ -132,6 +135,19 @@ auto flush_and_clear_serializer_buffer( std::vector& byte_buf ) -> void; +/** + * Unpacks and serializes the given msgpack bytes using kv serializer. + * @tparam encoded_variable_t + * @param serializer + * @param msgpack_bytes + * @return Whether the serialization is succeeded. + */ +template +[[nodiscard]] auto unpack_and_serialize_msgpack_bytes( + Serializer& serializer, + vector const& msgpack_bytes +) -> bool; + template [[nodiscard]] auto serialize_log_events( vector const& log_events, @@ -241,6 +257,20 @@ auto flush_and_clear_serializer_buffer( byte_buf.insert(byte_buf.cend(), view.begin(), view.end()); serializer.clear_ir_buf(); } + +template +auto unpack_and_serialize_msgpack_bytes( + Serializer& serializer, + vector const& msgpack_bytes +) -> bool { + msgpack::object_handle msgpack_oh; + msgpack::unpack( + msgpack_oh, + clp::size_checked_pointer_cast(msgpack_bytes.data()), + msgpack_bytes.size() + ); + return serializer.serialize_msgpack_map(msgpack_oh.get()); +} } // namespace /** @@ -971,3 +1001,86 @@ TEMPLATE_TEST_CASE( && 0 == num_bytes_read) ); } + +TEMPLATE_TEST_CASE( + "ffi_ir_stream_Serializer_serialize_msgpack", + "[clp][ffi][ir_stream][Serializer]", + four_byte_encoded_variable_t, + eight_byte_encoded_variable_t +) { + vector ir_buf; + + auto result{Serializer::create()}; + REQUIRE((false == result.has_error())); + + auto& serializer{result.value()}; + flush_and_clear_serializer_buffer(serializer, ir_buf); + + auto const empty_array = nlohmann::json::parse("[]"); + auto const empty_obj = nlohmann::json::parse("{}"); + REQUIRE(unpack_and_serialize_msgpack_bytes(serializer, nlohmann::json::to_msgpack(empty_obj))); + + // TODO: + // Before kv-pair IR Deserializer is implemented, we cannot test whether the serialized bytes + // can be correctly deserialized. We should improve the test coverage once we have a + // deserializer implementation. + + // Test encoding basic object + constexpr string_view cShortString{"short_string"}; + constexpr string_view cClpString{"uid=0, CPU usage: 99.99%, \"user_name\"=YScope"}; + nlohmann::json const basic_obj + = {{"int8_max", INT8_MAX}, + {"int8_min", INT8_MIN}, + {"int16_max", INT16_MAX}, + {"int16_min", INT16_MIN}, + {"int32_max", INT32_MAX}, + {"int32_min", INT32_MIN}, + {"int64_max", INT64_MAX}, + {"int64_min", INT64_MIN}, + {"float_zero", 0.0}, + {"float_pos", 1.01}, + {"float_neg", -1.01}, + {"true", true}, + {"false", false}, + {"string", cShortString}, + {"clp_string", cClpString}, + {"null", nullptr}, + {"empty_object", empty_obj}, + {"empty_array", empty_array}}; + + REQUIRE(unpack_and_serialize_msgpack_bytes(serializer, nlohmann::json::to_msgpack(basic_obj))); + + auto basic_array = empty_array; + basic_array.emplace_back(1); + basic_array.emplace_back(1.0); + basic_array.emplace_back(true); + basic_array.emplace_back(cShortString); + basic_array.emplace_back(cClpString); + basic_array.emplace_back(nullptr); + basic_array.emplace_back(empty_array); + for (auto const& element : basic_array) { + // Non-map objects should fail the serialization + REQUIRE( + (false + == unpack_and_serialize_msgpack_bytes( + serializer, + nlohmann::json::to_msgpack(element) + )) + ); + } + basic_array.emplace_back(empty_obj); + + // Recursively construct an object containing inner maps and inner arrays. + auto recursive_obj = basic_obj; + auto recursive_array = basic_array; + constexpr size_t cRecursiveDepth{5}; + for (size_t i{0}; i < cRecursiveDepth; ++i) { + recursive_array.emplace_back(recursive_obj); + recursive_obj.emplace("obj_" + std::to_string(i), recursive_obj); + recursive_obj.emplace("array_" + std::to_string(i), recursive_array); + REQUIRE(unpack_and_serialize_msgpack_bytes( + serializer, + nlohmann::json::to_msgpack(recursive_obj) + )); + } +}