1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#include <gtest/gtest.h>
#include <stddef.h>
#include <string>
#include "opentelemetry/nostd/function_ref.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/trace/trace_state.h"
namespace
{
using opentelemetry::trace::TraceState;
namespace nostd = opentelemetry::nostd;
// Random string of length 257. Used for testing strings with max length 256.
const char *kLongString =
"4aekid3he76zgytjavudqqeltyvu5zqio2lx7d92dlxlf0z4883irvxuwelsq27sx1mlrjg3r7ad3jeq09rjppyd9veorg"
"2nmihy4vilabfts8bsxruih0urusmjnglzl3iwpjinmo835dbojcrd73p56nw80v4xxrkye59ytmu5v84ysfa24d58ovv9"
"w1n54n0mhhf4z0mpv6oudywrp9vfoks6lrvxv3uihvbi2ihazf237kvt1nbsjn3kdvfdb";
// -------------------------- TraceState class tests ---------------------------
std::string create_ts_return_header(const std::string &header)
{
auto ts = TraceState::FromHeader(header);
return ts->ToHeader();
}
std::string header_with_max_members()
{
std::string header = "";
auto max_members = TraceState::kMaxKeyValuePairs;
for (int i = 0; i < max_members; i++)
{
std::string key = "key" + std::to_string(i);
std::string value = "value" + std::to_string(i);
header.append(key).append("=").append(value);
if (i != max_members - 1)
{
header += ",";
}
}
return header;
}
TEST(TraceStateTest, ValidateHeaderParsing)
{
auto max_trace_state_header = header_with_max_members();
struct
{
const char *input;
const char *expected;
} testcases[] = {{"k1=v1", "k1=v1"},
{"K1=V1", ""},
{"k1=v1,k2=v2,k3=v3", "k1=v1,k2=v2,k3=v3"},
{"k1=v1,k2=v2,,", "k1=v1,k2=v2"},
{"k1=v1,k2=v2,invalidmember", ""},
{"1a-2f@foo=bar1,a*/foo-_/bar=bar4", "1a-2f@foo=bar1,a*/foo-_/bar=bar4"},
{"1a-2f@foo=bar1,*/foo-_/bar=bar4", ""},
{",k1=v1", "k1=v1"},
{",", ""},
{",=,", ""},
{"", ""},
{max_trace_state_header.data(), max_trace_state_header.data()}};
for (auto &testcase : testcases)
{
EXPECT_EQ(create_ts_return_header(testcase.input), testcase.expected);
}
}
TEST(TraceStateTest, TraceStateGet)
{
std::string trace_state_header = header_with_max_members();
auto ts = TraceState::FromHeader(trace_state_header);
std::string value;
EXPECT_TRUE(ts->Get("key0", value));
EXPECT_EQ(value, "value0");
EXPECT_TRUE(ts->Get("key16", value));
EXPECT_EQ(value, "value16");
EXPECT_TRUE(ts->Get("key31", value));
EXPECT_EQ(value, "value31");
EXPECT_FALSE(ts->Get("key32", value));
}
TEST(TraceStateTest, TraceStateSet)
{
std::string trace_state_header = "k1=v1,k2=v2";
auto ts1 = TraceState::FromHeader(trace_state_header);
auto ts1_new = ts1->Set("k3", "v3");
EXPECT_EQ(ts1_new->ToHeader(), "k3=v3,k1=v1,k2=v2");
trace_state_header = header_with_max_members();
auto ts2 = TraceState::FromHeader(trace_state_header);
auto ts2_new =
ts2->Set("n_k1", "n_v1"); // adding to max list, should return copy of existing list
EXPECT_EQ(ts2_new->ToHeader(), trace_state_header);
trace_state_header = "k1=v1,k2=v2";
auto ts3 = TraceState::FromHeader(trace_state_header);
auto ts3_new = ts3->Set("*n_k1", "n_v1"); // adding invalid key, should return empty
EXPECT_EQ(ts3_new->ToHeader(), "");
}
TEST(TraceStateTest, TraceStateDelete)
{
std::string trace_state_header = "k1=v1,k2=v2,k3=v3";
auto ts1 = TraceState::FromHeader(trace_state_header);
auto ts1_new = ts1->Delete(std::string("k1"));
EXPECT_EQ(ts1_new->ToHeader(), "k2=v2,k3=v3");
trace_state_header = "k1=v1"; // single list member
auto ts2 = TraceState::FromHeader(trace_state_header);
auto ts2_new = ts2->Delete(std::string("k1"));
EXPECT_EQ(ts2_new->ToHeader(), "");
trace_state_header = "k1=v1"; // single list member, delete invalid entry
auto ts3 = TraceState::FromHeader(trace_state_header);
auto ts3_new = ts3->Delete(std::string("InvalidKey"));
EXPECT_EQ(ts3_new->ToHeader(), "");
}
TEST(TraceStateTest, Empty)
{
std::string trace_state_header = "";
auto ts = TraceState::FromHeader(trace_state_header);
EXPECT_TRUE(ts->Empty());
trace_state_header = "k1=v1,k2=v2";
auto ts1 = TraceState::FromHeader(trace_state_header);
EXPECT_FALSE(ts1->Empty());
}
TEST(TraceStateTest, GetAllEntries)
{
std::string trace_state_header = "k1=v1,k2=v2,k3=v3";
auto ts1 = TraceState::FromHeader(trace_state_header);
const int kNumPairs = 3;
nostd::string_view keys[kNumPairs] = {"k1", "k2", "k3"};
nostd::string_view values[kNumPairs] = {"v1", "v2", "v3"};
size_t index = 0;
ts1->GetAllEntries([&keys, &values, &index](nostd::string_view key, nostd::string_view value) {
EXPECT_EQ(key, keys[index]);
EXPECT_EQ(value, values[index]);
index++;
return true;
});
}
TEST(TraceStateTest, IsValidKey)
{
EXPECT_TRUE(TraceState::IsValidKey("valid-key23/*"));
EXPECT_FALSE(TraceState::IsValidKey("Invalid_key"));
EXPECT_FALSE(TraceState::IsValidKey("invalid$Key&"));
EXPECT_FALSE(TraceState::IsValidKey(""));
EXPECT_FALSE(TraceState::IsValidKey(kLongString));
}
TEST(TraceStateTest, IsValidValue)
{
EXPECT_TRUE(TraceState::IsValidValue("valid-val$%&~"));
EXPECT_FALSE(TraceState::IsValidValue("\tinvalid"));
EXPECT_FALSE(TraceState::IsValidValue("invalid="));
EXPECT_FALSE(TraceState::IsValidValue("invalid,val"));
EXPECT_FALSE(TraceState::IsValidValue(""));
EXPECT_FALSE(TraceState::IsValidValue(kLongString));
}
// Tests that keys and values don't depend on null terminators
TEST(TraceStateTest, MemorySafe)
{
std::string trace_state_header = "";
auto ts = TraceState::FromHeader(trace_state_header);
const int kNumPairs = 3;
nostd::string_view key_string = "test_key_1test_key_2test_key_3";
nostd::string_view val_string = "test_val_1test_val_2test_val_3";
nostd::string_view keys[kNumPairs] = {key_string.substr(0, 10), key_string.substr(10, 10),
key_string.substr(20, 10)};
nostd::string_view values[kNumPairs] = {val_string.substr(0, 10), val_string.substr(10, 10),
val_string.substr(20, 10)};
auto ts1 = ts->Set(keys[2], values[2]);
auto ts2 = ts1->Set(keys[1], values[1]);
auto ts3 = ts2->Set(keys[0], values[0]);
size_t index = 0;
ts3->GetAllEntries([&keys, &values, &index](nostd::string_view key, nostd::string_view value) {
EXPECT_EQ(key, keys[index]);
EXPECT_EQ(value, values[index]);
index++;
return true;
});
}
} // namespace
|