| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- //
- // json_layout_test.cxx
- // logger_test
- //
- // Created by Sam Jaffe on 4/13/19.
- //
- #include <gmock/gmock.h>
- #include "resource_factory/prototype_factory.hpp"
- #include "logger/detail/layout.h"
- #include "logger/log_manager.h"
- #include "logger/logpacket.h"
- #include "logger/properties.h"
- TEST(JsonLayoutTest, CanConstructWithNoConfig) {
- EXPECT_NO_THROW(logging::layouts::instance().get("JsonLayout", {}));
- }
- // Thursday, April 4, 2019 6:17:20 PM GMT
- namespace {
- constexpr const int NOW = 1554401840;
- }
- std::string const formatted_output = R"({
- "instant" : {
- "epochSecond" : 1554401840,
- "nanoOfSecond" : 123456000
- },
- "level" : "WARNING",
- "loggerName" : "UnitTest",
- "message" : "This is a test message"
- })";
- TEST(JsonLayoutTest, LogsInformationInJSON) {
- using namespace logging;
- auto playout = layouts::instance().get("JsonLayout", {});
- std::stringstream ss;
- playout->format(ss, {{NOW, 123456},
- level::warning,
- {},
- "UnitTest",
- "This is a test message"});
- using testing::Eq;
- EXPECT_THAT(ss.str(), Eq(formatted_output));
- }
- std::string const compact_output =
- "{\"instant\":{\"epochSecond\":"
- "1554401840,\"nanoOfSecond\":123456000},\"level\":\"WARNING\","
- "\"loggerName\":\"UnitTest\",\"message\":\"This is a test message\"}";
- TEST(JsonLayoutTest, CompactMeansNoWhitespace) {
- using namespace logging;
- using namespace logging::property;
- properties const props{_obj({{"compact", _v(true)}})};
- auto playout = layouts::instance().get("JsonLayout", props);
- std::stringstream ss;
- playout->format(ss, {{NOW, 123456},
- level::warning,
- {},
- "UnitTest",
- "This is a test message"});
- using testing::Eq;
- EXPECT_THAT(ss.str(), Eq(compact_output));
- }
- std::string const location_output = R"({
- "instant" : {
- "epochSecond" : 1554401840,
- "nanoOfSecond" : 123456000
- },
- "level" : "WARNING",
- "loggerName" : "UnitTest",
- "message" : "This is a test message",
- "source" : {
- "file" : "json_layout_test.cxx",
- "line" : 97,
- "method" : "TestBody"
- }
- })";
- TEST(JsonLayoutTest, ShowsLocationInfo) {
- using namespace logging;
- using namespace logging::property;
- properties const props{_obj({{"locationInfo", _v(true)}})};
- auto playout = layouts::instance().get("JsonLayout", props);
- std::stringstream ss;
- playout->format(ss, {{NOW, 123456},
- level::warning,
- log_here,
- "UnitTest",
- "This is a test message"});
- using testing::Eq;
- EXPECT_THAT(ss.str(), Eq(location_output));
- }
- TEST(JsonLayoutTest, EOLPropertyAppendsNewline) {
- using namespace logging;
- using namespace logging::property;
- properties const props{_obj({{"eventEol", _v(true)}})};
- auto playout = layouts::instance().get("JsonLayout", props);
- std::stringstream ss;
- playout->format(ss, {{NOW, 123456},
- level::warning,
- {},
- "UnitTest",
- "This is a test message"});
- using testing::EndsWith;
- using testing::StartsWith;
- EXPECT_THAT(ss.str(), StartsWith(formatted_output));
- EXPECT_THAT(ss.str(), EndsWith(logging::NEWLINE_TOKEN));
- }
- std::string const struct_output = R"({
- "instant" : {
- "epochSecond" : 1554401840,
- "nanoOfSecond" : 123456000
- },
- "level" : "WARNING",
- "loggerName" : "UnitTest",
- "message" : "{225}"
- })";
- struct example {
- int content;
- };
- std::ostream & operator<<(std::ostream & os, example const & ex) {
- return os << '{' << ex.content << '}';
- }
- std::string const struct_json_output = R"({
- "instant" : {
- "epochSecond" : 1554401840,
- "nanoOfSecond" : 123456000
- },
- "level" : "WARNING",
- "loggerName" : "UnitTest",
- "message" : {
- "content" : 225
- }
- })";
- struct json_example {
- int content;
- };
- std::ostream & operator<<(std::ostream & os, json_example const & ex) {
- return os << '{' << ex.content << '}';
- }
- Json::Value to_json(json_example const & ex) {
- Json::Value json;
- json["content"] = ex.content;
- return json;
- }
- TEST(JsonLayoutTest, MessageCanBeLoggedAsJSON) {
- using namespace logging;
- using namespace logging::property;
- properties const props{_obj({{"objectMessageAsJsonObject", _v(true)}})};
- auto playout = layouts::instance().get("JsonLayout", props);
- std::stringstream ss;
- json_example ex{225};
- playout->format(ss, {{NOW, 123456},
- level::warning,
- {},
- "UnitTest",
- {"This is a test message", ex}});
- using testing::Eq;
- EXPECT_THAT(ss.str(), Eq(struct_json_output));
- }
- TEST(JsonLayoutTest, ObjectLackingJsonDefaultsToString) {
- using namespace logging;
- using namespace logging::property;
- properties const props{_obj({{"objectMessageAsJsonObject", _v(true)}})};
- auto playout = layouts::instance().get("JsonLayout", props);
- std::stringstream ss;
- example ex{225};
- playout->format(ss, {{NOW, 123456},
- level::warning,
- {},
- "UnitTest",
- {"This is a test message", ex}});
- using testing::Eq;
- EXPECT_THAT(ss.str(), Eq(struct_output));
- }
- #include "header_test_obj.h"
- #include "logger/logger.h"
- using namespace logging;
- using namespace logging::property;
- // clang-format off
- properties const JSON_HEADER_SCHEMA{_obj({
- {"configuration", _obj({
- {"appenders", _obj({
- {"Stub", _obj({
- {"JsonLayout", _obj({
- {"complete", _v(true)},
- {"compact", _v(true)},
- {"eventEol", _v(true)}
- })}
- })}
- })},
- {"loggers", _obj({
- {"root", _obj({{"appenders", _obj({{"ref", _v("Stub")}})}})}
- })}
- })}
- })};
- // clang-format on
- using JsonLayoutHeaderTest = HeaderFooterTest;
- TEST_F(JsonLayoutHeaderTest, ProvidesArrayBounds) {
- {
- manager mgr;
- mgr.configure(JSON_HEADER_SCHEMA);
- }
- using testing::Eq;
- EXPECT_THAT(appender->sstream.str(), Eq("[]"));
- }
- TEST_F(JsonLayoutHeaderTest, SeparatesLogsWithComma) {
- using testing::EndsWith;
- using testing::StartsWith;
- manager mgr;
- mgr.configure(JSON_HEADER_SCHEMA);
- mgr.get().log(level::error, "HELLO");
- // Newline is printed as a part of the message...
- EXPECT_THAT(appender->sstream.str(), EndsWith("}\n"));
- appender->sstream.str("");
- mgr.get().log(level::error, "HELLO");
- // So the dividing comma gets attached to the next log
- EXPECT_THAT(appender->sstream.str(), StartsWith(",{"));
- }
- struct JsonLayoutIncompleteTest : public JsonLayoutHeaderTest {
- properties OVERRIDE{
- _obj({{"configuration",
- _obj({{"appenders",
- _obj({{"Stub",
- _obj({{"JsonLayout",
- _obj({{"complete", _v(false)}})}})}})}})}})};
- };
- TEST_F(JsonLayoutIncompleteTest, NoLogsMeansNoOutput) {
- {
- manager mgr;
- mgr.configure(JSON_HEADER_SCHEMA.mergedWith(OVERRIDE));
- }
- using testing::Eq;
- EXPECT_THAT(appender->sstream.str(), Eq(""));
- }
- TEST_F(JsonLayoutIncompleteTest, NonCompleteLogProducesJsonPerLine) {
- using testing::EndsWith;
- using testing::StartsWith;
- manager mgr;
- mgr.configure(JSON_HEADER_SCHEMA.mergedWith(OVERRIDE));
- mgr.get().log(level::error, "HELLO");
- // Newline is printed as a part of the message...
- EXPECT_THAT(appender->sstream.str(), EndsWith("}\n"));
- appender->sstream.str("");
- mgr.get().log(level::error, "HELLO");
- // So the dividing comma gets attached to the next log
- EXPECT_THAT(appender->sstream.str(), StartsWith("{"));
- }
|