baggage_test.cc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #include <assert.h>
  4. #include <gtest/gtest.h>
  5. #include <stddef.h>
  6. #include <string>
  7. #include <vector>
  8. #include "opentelemetry/baggage/baggage.h"
  9. #include "opentelemetry/common/kv_properties.h"
  10. #include "opentelemetry/nostd/function_ref.h"
  11. #include "opentelemetry/nostd/shared_ptr.h"
  12. #include "opentelemetry/nostd/string_view.h"
  13. using namespace opentelemetry::baggage;
  14. std::string header_with_custom_entries(size_t num_entries)
  15. {
  16. std::string header;
  17. for (size_t i = 0; i < num_entries; i++)
  18. {
  19. std::string key = "key" + std::to_string(i);
  20. std::string value = "value" + std::to_string(i);
  21. header.append(key).append("=").append(value);
  22. if (i != num_entries - 1)
  23. {
  24. header += ",";
  25. }
  26. }
  27. return header;
  28. }
  29. std::string header_with_custom_size(size_t key_value_size, size_t num_entries)
  30. {
  31. std::string header = "";
  32. for (size_t i = 0; i < num_entries; i++)
  33. {
  34. std::string str = std::to_string(i + 1);
  35. str += "=";
  36. assert(key_value_size > str.size());
  37. for (size_t j = str.size(); j < key_value_size; j++)
  38. {
  39. str += "a";
  40. }
  41. header += str + ',';
  42. }
  43. header.pop_back();
  44. return header;
  45. }
  46. TEST(BaggageTest, ValidateExtractHeader)
  47. {
  48. auto invalid_key_value_size_header = header_with_custom_size(Baggage::kMaxKeyValueSize + 5, 1);
  49. struct
  50. {
  51. const char *input;
  52. std::vector<const char *> keys;
  53. std::vector<const char *> values;
  54. } testcases[] = {
  55. {"k1=v1", {"k1"}, {"v1"}},
  56. {"k1=V1,K2=v2;metadata,k3=v3",
  57. {"k1", "K2", "k3"},
  58. {"V1", "v2;metadata", "v3"}}, // metadata is part of value
  59. {",k1 =v1,k2=v2 ; metadata,",
  60. {"k1", "k2"},
  61. {"v1", "v2; metadata"}}, // key and value are trimmed
  62. {"1a-2f%40foo=bar%251,a%2A%2Ffoo-_%2Fbar=bar+4",
  63. {"1a-2f@foo", "a*/foo-_/bar"},
  64. {"bar%1", "bar 4"}}, // decoding is done properly
  65. {"k1=v1,invalidmember,k2=v2", {"k1", "k2"}, {"v1", "v2"}}, // invalid member is skipped
  66. {",", {}, {}},
  67. {",=,", {}, {}},
  68. {"", {}, {}},
  69. {"k1=%5zv", {}, {}}, // invalid hex : invalid second digit
  70. {"k1=%5", {}, {}}, // invalid hex : missing two digits
  71. {"k%z2=v1", {}, {}}, // invalid hex : invalid first digit
  72. {"k%00=v1", {}, {}}, // key not valid
  73. {"k=v%7f", {}, {}}, // value not valid
  74. {invalid_key_value_size_header.data(), {}, {}}};
  75. for (auto &testcase : testcases)
  76. {
  77. auto baggage = Baggage::FromHeader(testcase.input);
  78. size_t index = 0;
  79. baggage->GetAllEntries([&testcase, &index](opentelemetry::nostd::string_view key,
  80. opentelemetry::nostd::string_view value) {
  81. EXPECT_EQ(key, testcase.keys[index]);
  82. EXPECT_EQ(value, testcase.values[index]);
  83. index++;
  84. return true;
  85. });
  86. }
  87. // For header with maximum threshold pairs, no pair is dropped
  88. auto max_pairs_header = header_with_custom_entries(Baggage::kMaxKeyValuePairs);
  89. EXPECT_EQ(Baggage::FromHeader(max_pairs_header.data())->ToHeader(), max_pairs_header.data());
  90. // Entries beyond threshold are dropped
  91. auto baggage = Baggage::FromHeader(header_with_custom_entries(Baggage::kMaxKeyValuePairs + 1));
  92. auto header = baggage->ToHeader();
  93. opentelemetry::common::KeyValueStringTokenizer kv_str_tokenizer(header);
  94. int expected_tokens = Baggage::kMaxKeyValuePairs;
  95. EXPECT_EQ(kv_str_tokenizer.NumTokens(), expected_tokens);
  96. // For header with total size more than threshold, baggage is empty
  97. int num_pairs_with_max_size = Baggage::kMaxSize / Baggage::kMaxKeyValueSize;
  98. auto invalid_total_size_header =
  99. header_with_custom_size(Baggage::kMaxKeyValueSize, num_pairs_with_max_size + 1);
  100. EXPECT_EQ(Baggage::FromHeader(invalid_total_size_header.data())->ToHeader(), "");
  101. }
  102. TEST(BaggageTest, ValidateInjectHeader)
  103. {
  104. struct
  105. {
  106. std::vector<const char *> keys;
  107. std::vector<const char *> values;
  108. const char *header;
  109. } testcases[] = {{{"k1"}, {"v1"}, "k1=v1"},
  110. {{"k3", "k2", "k1"}, {"", "v2", "v1"}, "k1=v1,k2=v2,k3="}, // empty value
  111. {{"1a-2f@foo", "a*/foo-_/bar"},
  112. {"bar%1", "bar 4"},
  113. "a%2A%2Ffoo-_%2Fbar=bar+4,1a-2f%40foo=bar%251"}, // encoding is done properly
  114. {{"foo 1"},
  115. {"bar 1; metadata ; ;;"},
  116. "foo+1=bar+1; metadata ; ;;"}}; // metadata is added without encoding
  117. for (auto &testcase : testcases)
  118. {
  119. opentelemetry::nostd::shared_ptr<Baggage> baggage(new Baggage{});
  120. for (size_t i = 0; i < testcase.keys.size(); i++)
  121. {
  122. baggage = baggage->Set(testcase.keys[i], testcase.values[i]);
  123. }
  124. EXPECT_EQ(baggage->ToHeader(), testcase.header);
  125. }
  126. }
  127. TEST(BaggageTest, BaggageGet)
  128. {
  129. auto header = header_with_custom_entries(Baggage::kMaxKeyValuePairs);
  130. auto baggage = Baggage::FromHeader(header);
  131. std::string value;
  132. EXPECT_TRUE(baggage->GetValue("key0", value));
  133. EXPECT_EQ(value, "value0");
  134. EXPECT_TRUE(baggage->GetValue("key16", value));
  135. EXPECT_EQ(value, "value16");
  136. EXPECT_TRUE(baggage->GetValue("key31", value));
  137. EXPECT_EQ(value, "value31");
  138. EXPECT_FALSE(baggage->GetValue("key181", value));
  139. }
  140. TEST(BaggageTest, BaggageSet)
  141. {
  142. std::string header = "k1=v1,k2=v2";
  143. auto baggage = Baggage::FromHeader(header);
  144. std::string value;
  145. baggage = baggage->Set("k3", "v3");
  146. EXPECT_TRUE(baggage->GetValue("k3", value));
  147. EXPECT_EQ(value, "v3");
  148. baggage = baggage->Set("k3", "v3_1"); // key should be updated with the latest value
  149. EXPECT_TRUE(baggage->GetValue("k3", value));
  150. EXPECT_EQ(value, "v3_1");
  151. header = header_with_custom_entries(Baggage::kMaxKeyValuePairs);
  152. baggage = Baggage::FromHeader(header);
  153. baggage = baggage->Set("key0", "0"); // updating on max list should work
  154. EXPECT_TRUE(baggage->GetValue("key0", value));
  155. EXPECT_EQ(value, "0");
  156. header = "k1=v1,k2=v2";
  157. baggage = Baggage::FromHeader(header);
  158. baggage = baggage->Set("", "n_v1"); // adding invalid key, should return copy of same baggage
  159. EXPECT_EQ(baggage->ToHeader(), header);
  160. header = "k1=v1,k2=v2";
  161. baggage = Baggage::FromHeader(header);
  162. baggage = baggage->Set("k1", "\x1A"); // adding invalid value, should return copy of same baggage
  163. EXPECT_EQ(baggage->ToHeader(), header);
  164. }
  165. TEST(BaggageTest, BaggageRemove)
  166. {
  167. auto header = header_with_custom_entries(Baggage::kMaxKeyValuePairs);
  168. auto baggage = Baggage::FromHeader(header);
  169. std::string value;
  170. // existing key is removed
  171. EXPECT_TRUE(baggage->GetValue("key0", value));
  172. auto new_baggage = baggage->Delete("key0");
  173. EXPECT_FALSE(new_baggage->GetValue("key0", value));
  174. // trying Delete on non existent key
  175. EXPECT_FALSE(baggage->GetValue("key181", value));
  176. auto new_baggage_2 = baggage->Delete("key181");
  177. EXPECT_FALSE(new_baggage_2->GetValue("key181", value));
  178. }
  179. TEST(BaggageTest, BaggageGetAll)
  180. {
  181. std::string baggage_header = "k1=v1,k2=v2,k3=v3";
  182. auto baggage = Baggage::FromHeader(baggage_header);
  183. const int kNumPairs = 3;
  184. opentelemetry::nostd::string_view keys[kNumPairs] = {"k1", "k2", "k3"};
  185. opentelemetry::nostd::string_view values[kNumPairs] = {"v1", "v2", "v3"};
  186. size_t index = 0;
  187. baggage->GetAllEntries([&keys, &values, &index](opentelemetry::nostd::string_view key,
  188. opentelemetry::nostd::string_view value) {
  189. EXPECT_EQ(key, keys[index]);
  190. EXPECT_EQ(value, values[index]);
  191. index++;
  192. return true;
  193. });
  194. }