core/unittest/processor/ProcessorParseJsonNativeUnittest.cpp (619 lines of code) (raw):
// Copyright 2023 iLogtail Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdlib>
#include "collection_pipeline/plugin/instance/ProcessorInstance.h"
#include "common/JsonUtil.h"
#include "config/CollectionConfig.h"
#include "models/LogEvent.h"
#include "plugin/processor/ProcessorParseJsonNative.h"
#include "plugin/processor/inner/ProcessorSplitLogStringNative.h"
#include "unittest/Unittest.h"
namespace logtail {
class ProcessorParseJsonNativeUnittest : public ::testing::Test {
public:
void SetUp() override { mContext.SetConfigName("project##config_0"); }
void TestInit();
void TestProcessJson();
void TestProcessJsonEscapedNullByte();
void TestAddLog();
void TestProcessEventKeepUnmatch();
void TestProcessEventDiscardUnmatch();
void TestProcessJsonContent();
void TestProcessJsonRaw();
void TestMultipleLines();
CollectionPipelineContext mContext;
};
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestInit);
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestAddLog);
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestProcessJson);
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestProcessJsonEscapedNullByte);
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestProcessEventKeepUnmatch);
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestProcessEventDiscardUnmatch);
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestProcessJsonContent);
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestProcessJsonRaw);
UNIT_TEST_CASE(ProcessorParseJsonNativeUnittest, TestMultipleLines);
PluginInstance::PluginMeta getPluginMeta() {
PluginInstance::PluginMeta pluginMeta{"1"};
return pluginMeta;
}
void ProcessorParseJsonNativeUnittest::TestMultipleLines() {
// error json
{
std::string inJson = R"({
"events" :
[
{
"contents" :
{
"content" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\"}\u0000{\"name\":\"Mike\",\"age\":25,\"is_student\":asdfsadf,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
}
]
})";
std::string expectJson = R"({
"events" :
[
{
"contents" :
{
"rawLog" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\"}",
"time" : "07/Jul/2022:10:30:28",
"url" : "POST /PutData?Category=YunOsAccountOpLog HTTP/1.1"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
},
{
"contents" :
{
"__raw_log__" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":asdfsadf,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}",
"rawLog" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":asdfsadf,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
}
]
})";
// ProcessorSplitLogStringNative
{
// make events
auto sourceBuffer = std::make_shared<SourceBuffer>();
PipelineEventGroup eventGroup(sourceBuffer);
eventGroup.FromJsonString(inJson);
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = true;
config["KeepingSourceWhenParseSucceed"] = true;
config["CopingRawLog"] = true;
config["RenamedSourceKey"] = "rawLog";
config["SplitChar"] = '\0';
// run function ProcessorSplitLogStringNative
ProcessorSplitLogStringNative processor;
processor.SetContext(mContext);
APSARA_TEST_TRUE_FATAL(processor.Init(config));
processor.Process(eventGroup);
// run function ProcessorParseJsonNative
ProcessorParseJsonNative& processorParseJsonNative = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processorParseJsonNative, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
processorParseJsonNative.Process(eventGroup);
// judge result
std::string outJson = eventGroup.ToJsonString();
APSARA_TEST_STREQ_FATAL(CompactJson(expectJson).c_str(), CompactJson(outJson).c_str());
}
}
{
std::string inJson = R"({
"events" :
[
{
"contents" :
{
"content" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\"}\u0000{\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
}
]
})";
std::string expectJson = R"({
"events" :
[
{
"contents" :
{
"rawLog" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\"}",
"time" : "07/Jul/2022:10:30:28",
"url" : "POST /PutData?Category=YunOsAccountOpLog HTTP/1.1"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
},
{
"contents" :
{
"address" : "{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"}",
"age":"25",
"courses":"[\"Math\",\"English\",\"Science\"]",
"is_student":"false",
"name":"Mike",
"rawLog" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}",
"scores":"{\"Math\":90,\"English\":85,\"Science\":95}"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
}
]
})";
// ProcessorSplitLogStringNative
{
// make events
auto sourceBuffer = std::make_shared<SourceBuffer>();
PipelineEventGroup eventGroup(sourceBuffer);
eventGroup.FromJsonString(inJson);
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = true;
config["KeepingSourceWhenParseSucceed"] = true;
config["CopingRawLog"] = true;
config["RenamedSourceKey"] = "rawLog";
config["SplitChar"] = '\0';
// run function ProcessorSplitLogStringNative
ProcessorSplitLogStringNative processor;
processor.SetContext(mContext);
APSARA_TEST_TRUE_FATAL(processor.Init(config));
processor.Process(eventGroup);
// run function ProcessorParseJsonNative
ProcessorParseJsonNative& processorParseJsonNative = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processorParseJsonNative, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
processorParseJsonNative.Process(eventGroup);
// judge result
std::string outJson = eventGroup.ToJsonString();
APSARA_TEST_STREQ_FATAL(CompactJson(expectJson).c_str(), CompactJson(outJson).c_str());
}
}
}
void ProcessorParseJsonNativeUnittest::TestInit() {
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = true;
config["KeepingSourceWhenParseSucceed"] = false;
config["CopingRawLog"] = false;
config["RenamedSourceKey"] = "rawLog";
// run function
ProcessorParseJsonNative& processor = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processor, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
}
void ProcessorParseJsonNativeUnittest::TestAddLog() {
// make config
Json::Value config;
config["SourceKey"] = "content";
ProcessorParseJsonNative& processor = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processor, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
auto eventGroup = PipelineEventGroup(std::make_shared<SourceBuffer>());
auto logEvent = eventGroup.CreateLogEvent();
char key[] = "key";
char value[] = "value";
processor.AddLog(key, value, *logEvent);
// check observability
// Todo: add metrics for check result
}
void ProcessorParseJsonNativeUnittest::TestProcessJsonEscapedNullByte() {
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = true;
config["KeepingSourceWhenParseSucceed"] = false;
config["CopingRawLog"] = false;
config["RenamedSourceKey"] = "rawLog";
// make events
auto sourceBuffer = std::make_shared<SourceBuffer>();
PipelineEventGroup eventGroup(sourceBuffer);
std::string inJson = R"({
"events" :
[
{
"contents" :
{
"content" : "{\"level\":\"ERROR\",\"time\":\"2024-07-04T06:59:23.078Z\",\"msg\":\"expect { or n, but found \\u0000, error found in #0 byte of ...\"}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
}
]
})";
eventGroup.FromJsonString(inJson);
// run function
ProcessorParseJsonNative& processor = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processor, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
std::vector<PipelineEventGroup> eventGroupList;
eventGroupList.emplace_back(std::move(eventGroup));
processorInstance.Process(eventGroupList);
// judge result
std::string expectJson = R"({
"events" :
[
{
"contents" :
{
"level": "ERROR",
"msg": "expect { or n, but found \u0000, error found in #0 byte of ...",
"time": "2024-07-04T06:59:23.078Z"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
}
]
})";
std::string outJson = eventGroupList[0].ToJsonString();
APSARA_TEST_STREQ_FATAL(CompactJson(expectJson).c_str(), CompactJson(outJson).c_str());
APSARA_TEST_GE_FATAL(processorInstance.mTotalProcessTimeMs->GetValue(), uint64_t(0));
}
void ProcessorParseJsonNativeUnittest::TestProcessJson() {
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = true;
config["KeepingSourceWhenParseSucceed"] = true;
config["CopingRawLog"] = true;
config["RenamedSourceKey"] = "rawLog";
// make events
auto sourceBuffer = std::make_shared<SourceBuffer>();
PipelineEventGroup eventGroup(sourceBuffer);
std::string inJson = R"({
"events" :
[
{
"contents" :
{
"content" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\"}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
},
{
"contents" :
{
"content" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
}
]
})";
eventGroup.FromJsonString(inJson);
// run function
ProcessorParseJsonNative& processor = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processor, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
std::vector<PipelineEventGroup> eventGroupList;
eventGroupList.emplace_back(std::move(eventGroup));
processorInstance.Process(eventGroupList);
// judge result
std::string expectJson = R"({
"events" :
[
{
"contents" :
{
"rawLog" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\"}",
"time" : "07/Jul/2022:10:30:28",
"url" : "POST /PutData?Category=YunOsAccountOpLog HTTP/1.1"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
},
{
"contents" :
{
"address" : "{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"}",
"age":"25",
"courses":"[\"Math\",\"English\",\"Science\"]",
"is_student":"false",
"name":"Mike",
"rawLog" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}",
"scores":"{\"Math\":90,\"English\":85,\"Science\":95}"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
}
]
})";
std::string outJson = eventGroupList[0].ToJsonString();
APSARA_TEST_STREQ_FATAL(CompactJson(expectJson).c_str(), CompactJson(outJson).c_str());
APSARA_TEST_GE_FATAL(processorInstance.mTotalProcessTimeMs->GetValue(), uint64_t(0));
}
void ProcessorParseJsonNativeUnittest::TestProcessJsonContent() {
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = true;
config["KeepingSourceWhenParseSucceed"] = true;
config["CopingRawLog"] = true;
config["RenamedSourceKey"] = "rawLog";
// make events
// the first event has key "content" in json key with overwrites sourceKey "content"
// the second event doesn't have key "content" in json
// after parsing, the first event's content should be the value in json, the original content should be the value of
// "rawLog" the second event's content should be dropped, the original content should be the value of "rawLog"
auto sourceBuffer = std::make_shared<SourceBuffer>();
PipelineEventGroup eventGroup(sourceBuffer);
std::string inJson = R"({
"events" :
[
{
"contents" :
{
"content" : "{\"content\":\"content_test\",\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
},
{
"contents" :
{
"content" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678902,
"type" : 1
}
]
})";
eventGroup.FromJsonString(inJson);
// run function
ProcessorParseJsonNative& processor = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processor, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
std::vector<PipelineEventGroup> eventGroupList;
eventGroupList.emplace_back(std::move(eventGroup));
processorInstance.Process(eventGroupList);
// judge result
std::string expectJson = R"({
"events" :
[
{
"contents" :
{
"address" : "{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"}",
"age":"25",
"content":"content_test",
"courses":"[\"Math\",\"English\",\"Science\"]",
"is_student":"false",
"name":"Mike",
"rawLog" : "{\"content\":\"content_test\",\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}",
"scores":"{\"Math\":90,\"English\":85,\"Science\":95}"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
},
{
"contents" :
{
"address" : "{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"}",
"age":"25",
"courses":"[\"Math\",\"English\",\"Science\"]",
"is_student":"false",
"name":"Mike",
"rawLog" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}",
"scores":"{\"Math\":90,\"English\":85,\"Science\":95}"
},
"timestamp" : 12345678902,
"timestampNanosecond" : 0,
"type" : 1
}
]
})";
std::string outJson = eventGroupList[0].ToJsonString();
APSARA_TEST_STREQ_FATAL(CompactJson(expectJson).c_str(), CompactJson(outJson).c_str());
APSARA_TEST_GE_FATAL(processorInstance.mTotalProcessTimeMs->GetValue(), uint64_t(0));
}
void ProcessorParseJsonNativeUnittest::TestProcessJsonRaw() {
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = true;
config["KeepingSourceWhenParseSucceed"] = true;
config["CopingRawLog"] = true;
config["RenamedSourceKey"] = "rawLog";
// make events
// the first event has key "rawLog" in json key with overwrites rawLogTag "rawLog"
// the second event doesn't have key "rawLog" in json
// after parsing, the first event's rawLog should be the value in json, the original content should be discarded
// the second event's rawLog should be the original content
auto sourceBuffer = std::make_shared<SourceBuffer>();
PipelineEventGroup eventGroup(sourceBuffer);
std::string inJson = R"({
"events" :
[
{
"contents" :
{
"content" : "{\"rawLog\":\"content_test\",\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
},
{
"contents" :
{
"content" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}"
},
"timestampNanosecond" : 0,
"timestamp" : 12345678902,
"type" : 1
}
]
})";
eventGroup.FromJsonString(inJson);
// run function
ProcessorParseJsonNative& processor = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processor, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
std::vector<PipelineEventGroup> eventGroupList;
eventGroupList.emplace_back(std::move(eventGroup));
processorInstance.Process(eventGroupList);
// judge result
std::string expectJson = R"({
"events" :
[
{
"contents" :
{
"address" : "{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"}",
"age":"25",
"courses":"[\"Math\",\"English\",\"Science\"]",
"is_student":"false",
"name":"Mike",
"rawLog" : "content_test",
"scores":"{\"Math\":90,\"English\":85,\"Science\":95}"
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
},
{
"contents" :
{
"address" : "{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"}",
"age":"25",
"courses":"[\"Math\",\"English\",\"Science\"]",
"is_student":"false",
"name":"Mike",
"rawLog" : "{\"name\":\"Mike\",\"age\":25,\"is_student\":false,\"address\":{\"city\":\"Hangzhou\",\"postal_code\":\"100000\"},\"courses\":[\"Math\",\"English\",\"Science\"],\"scores\":{\"Math\":90,\"English\":85,\"Science\":95}}",
"scores":"{\"Math\":90,\"English\":85,\"Science\":95}"
},
"timestamp" : 12345678902,
"timestampNanosecond" : 0,
"type" : 1
}
]
})";
std::string outJson = eventGroupList[0].ToJsonString();
APSARA_TEST_STREQ_FATAL(CompactJson(expectJson).c_str(), CompactJson(outJson).c_str());
APSARA_TEST_GE_FATAL(processorInstance.mTotalProcessTimeMs->GetValue(), uint64_t(0));
}
void ProcessorParseJsonNativeUnittest::TestProcessEventKeepUnmatch() {
// make config
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = true;
config["KeepingSourceWhenParseSucceed"] = false;
config["CopingRawLog"] = false;
config["RenamedSourceKey"] = "rawLog";
// make events
auto sourceBuffer = std::make_shared<SourceBuffer>();
PipelineEventGroup eventGroup(sourceBuffer);
std::string inJson = R"({
"events" :
[
{
"contents" :
{
"content" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\""
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
}
]
})";
eventGroup.FromJsonString(inJson);
// run function
ProcessorParseJsonNative& processor = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processor, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
std::vector<PipelineEventGroup> eventGroupList;
eventGroupList.emplace_back(std::move(eventGroup));
processorInstance.Process(eventGroupList);
int count = 1;
// check observablity
APSARA_TEST_EQUAL_FATAL(uint64_t(count), processorInstance.mInEventsTotal->GetValue());
APSARA_TEST_EQUAL_FATAL(uint64_t(count), processorInstance.mOutEventsTotal->GetValue());
APSARA_TEST_EQUAL_FATAL(uint64_t(0), processor.mDiscardedEventsTotal->GetValue());
APSARA_TEST_EQUAL_FATAL(uint64_t(count), processor.mOutFailedEventsTotal->GetValue());
// judge result
std::string expectJson = R"({
"events" :
[
{
"contents" :
{
"rawLog" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\""
},
"timestamp" : 12345678901,
"timestampNanosecond" : 0,
"type" : 1
}
]
})";
std::string outJson = eventGroupList[0].ToJsonString();
APSARA_TEST_STREQ_FATAL(CompactJson(expectJson).c_str(), CompactJson(outJson).c_str());
APSARA_TEST_GE_FATAL(processorInstance.mTotalProcessTimeMs->GetValue(), uint64_t(0));
}
void ProcessorParseJsonNativeUnittest::TestProcessEventDiscardUnmatch() {
// make config
Json::Value config;
config["SourceKey"] = "content";
config["KeepingSourceWhenParseFail"] = false;
config["KeepingSourceWhenParseSucceed"] = false;
config["CopingRawLog"] = false;
config["RenamedSourceKey"] = "rawLog";
// make events
auto sourceBuffer = std::make_shared<SourceBuffer>();
PipelineEventGroup eventGroup(sourceBuffer);
std::string inJson = R"({
"events" :
[
{
"contents" :
{
"content" : "{\"url\": \"POST /PutData?Category=YunOsAccountOpLog HTTP/1.1\",\"time\": \"07/Jul/2022:10:30:28\""
},
"timestampNanosecond" : 0,
"timestamp" : 12345678901,
"type" : 1
}
]
})";
eventGroup.FromJsonString(inJson);
// run function
ProcessorParseJsonNative& processor = *(new ProcessorParseJsonNative);
ProcessorInstance processorInstance(&processor, getPluginMeta());
APSARA_TEST_TRUE_FATAL(processorInstance.Init(config, mContext));
std::vector<PipelineEventGroup> eventGroupList;
eventGroupList.emplace_back(std::move(eventGroup));
processorInstance.Process(eventGroupList);
int count = 1;
// check observablity
APSARA_TEST_EQUAL_FATAL(uint64_t(count), processorInstance.mInEventsTotal->GetValue());
// discard unmatch, so output is 0
APSARA_TEST_EQUAL_FATAL(uint64_t(0), processorInstance.mOutEventsTotal->GetValue());
// event group size is not 0
APSARA_TEST_NOT_EQUAL_FATAL(uint64_t(0), processorInstance.mOutSizeBytes->GetValue());
APSARA_TEST_EQUAL_FATAL(uint64_t(count), processor.mDiscardedEventsTotal->GetValue());
APSARA_TEST_EQUAL_FATAL(uint64_t(count), processor.mOutFailedEventsTotal->GetValue());
std::string outJson = eventGroupList[0].ToJsonString();
APSARA_TEST_STREQ_FATAL("null", CompactJson(outJson).c_str());
APSARA_TEST_GE_FATAL(processorInstance.mTotalProcessTimeMs->GetValue(), uint64_t(0));
}
} // namespace logtail
UNIT_TEST_MAIN