* This file is part of the MindStudio project.
* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* MindStudio is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*/
#include <gtest/gtest.h>
#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <limits>
#include <cstdint>
#include <random>
#include <mutex>
#include <google/protobuf/util/json_util.h>
#include "opentelemetry/proto/trace/v1/trace.pb.h"
#include "opentelemetry/proto/collector/trace/v1/trace_service.pb.h"
#include "msServiceProfiler/ServiceProfilerInterface.h"
#include "msServiceProfiler/Log.h"
#include "msServiceProfiler/ServiceTracer.h"
#include "msServiceProfiler/Tracer.h"
extern opentelemetry::proto::resource::v1::Resource &getResourceProto();
extern bool hexStr2TraceId(const std::string &traceStr, TraceId &traceId);
extern bool hexStr2SpanId(const std::string &spanStr, SpanId &spanId);
extern void SpanFillCtxData(TRACE_SPAN_DATA spanData, TraceId traceid, SpanId spanid, SpanId pSpanid);
using SpanPtr = opentelemetry::proto::trace::v1::Span *;
template <int cnt>
std::array<uint8_t, cnt> stringToByteArray(const std::string &str)
{
std::array<uint8_t, cnt> arr;
std::copy(str.begin(), str.end(), arr.begin());
return arr;
}
class TracerTest : public ::testing::Test {
protected:
void SetUp() override
{
}
void TearDown() override
{
}
};
TEST_F(TracerTest, TestResAddAttr)
{
ResAddAttr("key1", "value1");
ResAddAttr("key2", "value2");
EXPECT_EQ(getResourceProto().attributes_size(), 2);
EXPECT_EQ(getResourceProto().attributes(0).key(), "key1");
EXPECT_EQ(getResourceProto().attributes(0).value().string_value(), "value1");
EXPECT_EQ(getResourceProto().attributes(1).key(), "key2");
EXPECT_EQ(getResourceProto().attributes(1).value().string_value(), "value2");
}
TEST_F(TracerTest, TestNewSpanData)
{
TRACE_SPAN_DATA spanData = NewSpanData("testSpan");
SpanPtr span_pb = (SpanPtr)spanData;
EXPECT_EQ(span_pb->name(), "testSpan");
EXPECT_EQ(span_pb->kind(), opentelemetry::proto::trace::v1::Span_SpanKind_SPAN_KIND_SERVER);
EXPECT_EQ(span_pb->flags(), opentelemetry::proto::trace::v1::SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK);
delete span_pb;
}
TEST_F(TracerTest, TestSpanActivate)
{
TRACE_SPAN_DATA spanData = NewSpanData("testSpan");
SpanPtr span_pb = (SpanPtr)spanData;
uint64_t startTime = 1234567890;
SpanActivate(spanData, startTime);
EXPECT_EQ(span_pb->start_time_unix_nano(), startTime);
delete span_pb;
}
TEST_F(TracerTest, TestSpanFillCtxData)
{
TRACE_SPAN_DATA spanData = NewSpanData("testSpan");
SpanPtr span_pb = (SpanPtr)spanData;
TraceId traceId = {0, 0};
SpanId spanId(0);
SpanId parentSpanId(0);
EXPECT_TRUE(hexStr2TraceId("0af7651916cd43dd8448eb211c80319c", traceId));
EXPECT_TRUE(hexStr2SpanId("b7ad6b7169203331", spanId));
EXPECT_TRUE(hexStr2SpanId("a0a0a0a0a0a0a0a0", parentSpanId));
SpanFillCtxData(spanData, traceId, spanId, parentSpanId);
EXPECT_EQ(stringToByteArray<16>(span_pb->trace_id()), traceId.as_char);
EXPECT_EQ(stringToByteArray<8>(span_pb->span_id()), spanId.as_char);
EXPECT_EQ(stringToByteArray<8>(span_pb->parent_span_id()), parentSpanId.as_char);
delete span_pb;
}
TEST_F(TracerTest, TestSpanAddAttribute)
{
TRACE_SPAN_DATA spanData = NewSpanData("testSpan");
SpanPtr span_pb = (SpanPtr)spanData;
SpanAddAttribute(spanData, "attr1", "value1");
SpanAddAttribute(spanData, "attr2", "value2");
EXPECT_EQ(span_pb->attributes_size(), 2);
EXPECT_EQ(span_pb->attributes(0).key(), "attr1");
EXPECT_EQ(span_pb->attributes(0).value().string_value(), "value1");
EXPECT_EQ(span_pb->attributes(1).key(), "attr2");
EXPECT_EQ(span_pb->attributes(1).value().string_value(), "value2");
delete span_pb;
}
TEST_F(TracerTest, TestSpanSetStatus)
{
TRACE_SPAN_DATA spanData = NewSpanData("testSpan");
SpanPtr span_pb = (SpanPtr)spanData;
SpanSetStatus(spanData, true, "");
EXPECT_EQ(span_pb->status().code(), opentelemetry::proto::trace::v1::Status::STATUS_CODE_OK);
EXPECT_EQ(span_pb->status().message(), "");
SpanSetStatus(spanData, false, "Error message");
EXPECT_EQ(span_pb->status().code(), opentelemetry::proto::trace::v1::Status::STATUS_CODE_ERROR);
delete span_pb;
}
TEST_F(TracerTest, TestSpanEndAndFree)
{
TRACE_SPAN_DATA spanData = NewSpanData("testSpan");
SpanPtr span_pb = (SpanPtr)spanData;
SpanEndAndFree(spanData, "testModule");
}
TEST_F(TracerTest, TestParseHttpCtx)
{
TraceId traceId = {0, 0};
SpanId spanId(0);
EXPECT_TRUE(hexStr2TraceId("0af7651916cd43dd8448eb211c80319c", traceId));
EXPECT_TRUE(hexStr2SpanId("b7ad6b7169203331", spanId));
TraceContextInfo ctx1 = ParseHttpCtx("00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01", "");
EXPECT_EQ(std::get<0>(ctx1).as_char, traceId.as_char);
EXPECT_EQ(std::get<1>(ctx1).as_char, spanId.as_char);
EXPECT_TRUE(std::get<2>(ctx1));
TraceContextInfo ctx2 = ParseHttpCtx("", "0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-1");
EXPECT_EQ(std::get<0>(ctx2).as_char, traceId.as_char);
EXPECT_EQ(std::get<1>(ctx2).as_char, spanId.as_char);
EXPECT_TRUE(std::get<2>(ctx2));
TraceContextInfo ctx3 = ParseHttpCtx("", "0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-0");
EXPECT_EQ(std::get<0>(ctx3).as_char, traceId.as_char);
EXPECT_EQ(std::get<1>(ctx3).as_char, spanId.as_char);
EXPECT_FALSE(std::get<2>(ctx3));
TraceContextInfo ctx4 = ParseHttpCtx("", "");
EXPECT_EQ(std::get<0>(ctx4).as_char, (TraceId{0, 0}).as_char);
EXPECT_EQ(std::get<1>(ctx4).as_char, SpanId(0).as_char);
EXPECT_FALSE(std::get<2>(ctx4));
}