resource_test.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #include <gtest/gtest.h>
  4. #include <stdint.h>
  5. #include <cstdlib>
  6. #include <map>
  7. #include <string>
  8. #include <unordered_map>
  9. #include <utility>
  10. #include "opentelemetry/nostd/variant.h"
  11. #include "opentelemetry/sdk/common/attribute_utils.h"
  12. #include "opentelemetry/sdk/resource/resource.h"
  13. #include "opentelemetry/sdk/resource/resource_detector.h"
  14. #include "opentelemetry/sdk/version/version.h"
  15. #include "opentelemetry/semconv/service_attributes.h"
  16. #include "opentelemetry/semconv/telemetry_attributes.h"
  17. #if defined(_MSC_VER)
  18. # include "opentelemetry/sdk/common/env_variables.h"
  19. using opentelemetry::sdk::common::setenv;
  20. using opentelemetry::sdk::common::unsetenv;
  21. #endif
  22. using namespace opentelemetry::sdk::resource;
  23. namespace nostd = opentelemetry::nostd;
  24. namespace semconv = opentelemetry::semconv;
  25. class TestResource : public Resource
  26. {
  27. public:
  28. TestResource(const ResourceAttributes &attributes = ResourceAttributes(),
  29. const std::string &schema_url = {})
  30. : Resource(attributes, schema_url)
  31. {}
  32. };
  33. class TestResourceDetector : public ResourceDetector
  34. {
  35. public:
  36. TestResourceDetector() = default;
  37. Resource Detect() noexcept override { return Create(attributes, schema_url); }
  38. ResourceAttributes attributes;
  39. std::string schema_url;
  40. };
  41. TEST(ResourceTest, create_without_servicename)
  42. {
  43. ResourceAttributes expected_attributes = {
  44. {"service", "backend"},
  45. {"version", static_cast<uint32_t>(1)},
  46. {"cost", 234.23},
  47. {semconv::telemetry::kTelemetrySdkLanguage, "cpp"},
  48. {semconv::telemetry::kTelemetrySdkName, "opentelemetry"},
  49. {semconv::telemetry::kTelemetrySdkVersion, OPENTELEMETRY_SDK_VERSION},
  50. {semconv::service::kServiceName, "unknown_service"}};
  51. ResourceAttributes attributes = {
  52. {"service", "backend"}, {"version", static_cast<uint32_t>(1)}, {"cost", 234.23}};
  53. auto resource = Resource::Create(attributes);
  54. auto received_attributes = resource.GetAttributes();
  55. for (auto &e : received_attributes)
  56. {
  57. EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
  58. if (expected_attributes.find(e.first) != expected_attributes.end())
  59. {
  60. if (e.first == "version")
  61. EXPECT_EQ(nostd::get<uint32_t>(expected_attributes.find(e.first)->second),
  62. nostd::get<uint32_t>(e.second));
  63. else if (e.first == "cost")
  64. EXPECT_EQ(nostd::get<double>(expected_attributes.find(e.first)->second),
  65. nostd::get<double>(e.second));
  66. else
  67. EXPECT_EQ(opentelemetry::nostd::get<std::string>(expected_attributes.find(e.first)->second),
  68. opentelemetry::nostd::get<std::string>(e.second));
  69. }
  70. }
  71. EXPECT_EQ(received_attributes.size(), expected_attributes.size()); // for missing service.name
  72. }
  73. TEST(ResourceTest, create_with_servicename)
  74. {
  75. ResourceAttributes expected_attributes = {
  76. {"version", static_cast<uint32_t>(1)},
  77. {"cost", 234.23},
  78. {semconv::telemetry::kTelemetrySdkLanguage, "cpp"},
  79. {semconv::telemetry::kTelemetrySdkName, "opentelemetry"},
  80. {semconv::telemetry::kTelemetrySdkVersion, OPENTELEMETRY_SDK_VERSION},
  81. {semconv::service::kServiceName, "backend"},
  82. };
  83. ResourceAttributes attributes = {
  84. {"service.name", "backend"}, {"version", static_cast<uint32_t>(1)}, {"cost", 234.23}};
  85. auto resource = Resource::Create(attributes);
  86. auto received_attributes = resource.GetAttributes();
  87. for (auto &e : received_attributes)
  88. {
  89. EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
  90. if (expected_attributes.find(e.first) != expected_attributes.end())
  91. {
  92. if (e.first == "version")
  93. EXPECT_EQ(nostd::get<uint32_t>(expected_attributes.find(e.first)->second),
  94. nostd::get<uint32_t>(e.second));
  95. else if (e.first == "cost")
  96. EXPECT_EQ(nostd::get<double>(expected_attributes.find(e.first)->second),
  97. nostd::get<double>(e.second));
  98. else
  99. EXPECT_EQ(nostd::get<std::string>(expected_attributes.find(e.first)->second),
  100. nostd::get<std::string>(e.second));
  101. }
  102. }
  103. EXPECT_EQ(received_attributes.size(), expected_attributes.size()); // for missing service.name
  104. }
  105. TEST(ResourceTest, create_with_emptyatrributes)
  106. {
  107. ResourceAttributes expected_attributes = {
  108. {semconv::telemetry::kTelemetrySdkLanguage, "cpp"},
  109. {semconv::telemetry::kTelemetrySdkName, "opentelemetry"},
  110. {semconv::telemetry::kTelemetrySdkVersion, OPENTELEMETRY_SDK_VERSION},
  111. {semconv::service::kServiceName, "unknown_service"},
  112. };
  113. ResourceAttributes attributes = {};
  114. auto resource = Resource::Create(attributes);
  115. auto received_attributes = resource.GetAttributes();
  116. for (auto &e : received_attributes)
  117. {
  118. EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
  119. if (expected_attributes.find(e.first) != expected_attributes.end())
  120. {
  121. EXPECT_EQ(opentelemetry::nostd::get<std::string>(expected_attributes.find(e.first)->second),
  122. opentelemetry::nostd::get<std::string>(e.second));
  123. }
  124. }
  125. EXPECT_EQ(received_attributes.size(), expected_attributes.size()); // for missing service.name
  126. }
  127. TEST(ResourceTest, create_with_schemaurl)
  128. {
  129. const std::string schema_url = "https://opentelemetry.io/schemas/1.2.0";
  130. ResourceAttributes attributes = {};
  131. auto resource = Resource::Create(attributes, schema_url);
  132. const auto &received_schema_url = resource.GetSchemaURL();
  133. EXPECT_EQ(received_schema_url, schema_url);
  134. }
  135. TEST(ResourceTest, Merge)
  136. {
  137. TestResource resource1(ResourceAttributes({{"service", "backend"}}));
  138. TestResource resource2(ResourceAttributes({{"host", "service-host"}}));
  139. std::map<std::string, std::string> expected_attributes = {{"service", "backend"},
  140. {"host", "service-host"}};
  141. auto merged_resource = resource1.Merge(resource2);
  142. auto received_attributes = merged_resource.GetAttributes();
  143. for (auto &e : received_attributes)
  144. {
  145. EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
  146. if (expected_attributes.find(e.first) != expected_attributes.end())
  147. {
  148. EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
  149. }
  150. }
  151. EXPECT_EQ(received_attributes.size(), expected_attributes.size());
  152. }
  153. TEST(ResourceTest, MergeEmptyString)
  154. {
  155. TestResource resource1({{"service", "backend"}, {"host", "service-host"}});
  156. TestResource resource2({{"service", ""}, {"host", "another-service-host"}});
  157. std::map<std::string, std::string> expected_attributes = {{"service", ""},
  158. {"host", "another-service-host"}};
  159. auto merged_resource = resource1.Merge(resource2);
  160. auto received_attributes = merged_resource.GetAttributes();
  161. for (auto &e : received_attributes)
  162. {
  163. EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
  164. if (expected_attributes.find(e.first) != expected_attributes.end())
  165. {
  166. EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
  167. }
  168. }
  169. EXPECT_EQ(received_attributes.size(), expected_attributes.size());
  170. }
  171. TEST(ResourceTest, MergeSchemaUrl)
  172. {
  173. const std::string url = "https://opentelemetry.io/schemas/v3.1.4";
  174. TestResource resource_empty_url({}, "");
  175. TestResource resource_some_url({}, url);
  176. TestResource resource_different_url({}, "different");
  177. // Specified behavior:
  178. auto merged_both_empty = resource_empty_url.Merge(resource_empty_url);
  179. EXPECT_TRUE(merged_both_empty.GetSchemaURL().empty());
  180. auto merged_old_empty = resource_empty_url.Merge(resource_some_url);
  181. EXPECT_EQ(merged_old_empty.GetSchemaURL(), url);
  182. auto merged_updating_empty = resource_some_url.Merge(resource_empty_url);
  183. EXPECT_EQ(merged_updating_empty.GetSchemaURL(), url);
  184. auto merged_same_url = resource_some_url.Merge(resource_some_url);
  185. EXPECT_EQ(merged_same_url.GetSchemaURL(), url);
  186. // Implementation-defined behavior:
  187. auto merged_different_url = resource_different_url.Merge(resource_some_url);
  188. EXPECT_EQ(merged_different_url.GetSchemaURL(), url);
  189. }
  190. #ifndef NO_GETENV
  191. TEST(ResourceTest, OtelResourceDetector)
  192. {
  193. std::map<std::string, std::string> expected_attributes = {{"k", "v"}};
  194. setenv("OTEL_RESOURCE_ATTRIBUTES", "k=v", 1);
  195. OTELResourceDetector detector;
  196. auto resource = detector.Detect();
  197. auto received_attributes = resource.GetAttributes();
  198. for (auto &e : received_attributes)
  199. {
  200. EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
  201. if (expected_attributes.find(e.first) != expected_attributes.end())
  202. {
  203. EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
  204. }
  205. }
  206. EXPECT_EQ(received_attributes.size(), expected_attributes.size());
  207. unsetenv("OTEL_RESOURCE_ATTRIBUTES");
  208. }
  209. TEST(ResourceTest, OtelResourceDetectorServiceNameOverride)
  210. {
  211. std::map<std::string, std::string> expected_attributes = {{"service.name", "new_name"}};
  212. setenv("OTEL_RESOURCE_ATTRIBUTES", "service.name=old_name", 1);
  213. setenv("OTEL_SERVICE_NAME", "new_name", 1);
  214. OTELResourceDetector detector;
  215. auto resource = detector.Detect();
  216. auto received_attributes = resource.GetAttributes();
  217. for (auto &e : received_attributes)
  218. {
  219. EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
  220. if (expected_attributes.find(e.first) != expected_attributes.end())
  221. {
  222. EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
  223. }
  224. }
  225. EXPECT_EQ(received_attributes.size(), expected_attributes.size());
  226. unsetenv("OTEL_SERVICE_NAME");
  227. unsetenv("OTEL_RESOURCE_ATTRIBUTES");
  228. }
  229. TEST(ResourceTest, OtelResourceDetectorEmptyEnv)
  230. {
  231. std::map<std::string, std::string> expected_attributes = {};
  232. unsetenv("OTEL_RESOURCE_ATTRIBUTES");
  233. OTELResourceDetector detector;
  234. auto resource = detector.Detect();
  235. auto received_attributes = resource.GetAttributes();
  236. for (auto &e : received_attributes)
  237. {
  238. EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
  239. if (expected_attributes.find(e.first) != expected_attributes.end())
  240. {
  241. EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
  242. }
  243. }
  244. EXPECT_EQ(received_attributes.size(), expected_attributes.size());
  245. }
  246. #endif
  247. TEST(ResourceTest, DerivedResourceDetector)
  248. {
  249. TestResourceDetector detector;
  250. detector.attributes = {{"key", "value"}};
  251. detector.schema_url = "https://opentelemetry.io/schemas/v3.1.4";
  252. const auto resource = detector.Detect();
  253. const auto received_attributes = resource.GetAttributes();
  254. EXPECT_EQ(received_attributes.size(), 1);
  255. EXPECT_EQ(resource.GetSchemaURL(), detector.schema_url);
  256. EXPECT_TRUE(received_attributes.find("key") != received_attributes.end());
  257. }