| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 | // Copyright The OpenTelemetry Authors// SPDX-License-Identifier: Apache-2.0#include <gtest/gtest.h>#include <stdint.h>#include <cstdlib>#include <map>#include <string>#include <unordered_map>#include <utility>#include "opentelemetry/nostd/variant.h"#include "opentelemetry/sdk/common/attribute_utils.h"#include "opentelemetry/sdk/resource/resource.h"#include "opentelemetry/sdk/resource/resource_detector.h"#include "opentelemetry/sdk/version/version.h"#include "opentelemetry/semconv/service_attributes.h"#include "opentelemetry/semconv/telemetry_attributes.h"#if defined(_MSC_VER)#  include "opentelemetry/sdk/common/env_variables.h"using opentelemetry::sdk::common::setenv;using opentelemetry::sdk::common::unsetenv;#endifusing namespace opentelemetry::sdk::resource;namespace nostd   = opentelemetry::nostd;namespace semconv = opentelemetry::semconv;class TestResource : public Resource{public:  TestResource(const ResourceAttributes &attributes = ResourceAttributes(),               const std::string &schema_url        = {})      : Resource(attributes, schema_url)  {}};class TestResourceDetector : public ResourceDetector{public:  TestResourceDetector() = default;  Resource Detect() noexcept override { return Create(attributes, schema_url); }  ResourceAttributes attributes;  std::string schema_url;};TEST(ResourceTest, create_without_servicename){  ResourceAttributes expected_attributes = {      {"service", "backend"},      {"version", static_cast<uint32_t>(1)},      {"cost", 234.23},      {semconv::telemetry::kTelemetrySdkLanguage, "cpp"},      {semconv::telemetry::kTelemetrySdkName, "opentelemetry"},      {semconv::telemetry::kTelemetrySdkVersion, OPENTELEMETRY_SDK_VERSION},      {semconv::service::kServiceName, "unknown_service"}};  ResourceAttributes attributes = {      {"service", "backend"}, {"version", static_cast<uint32_t>(1)}, {"cost", 234.23}};  auto resource            = Resource::Create(attributes);  auto received_attributes = resource.GetAttributes();  for (auto &e : received_attributes)  {    EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());    if (expected_attributes.find(e.first) != expected_attributes.end())    {      if (e.first == "version")        EXPECT_EQ(nostd::get<uint32_t>(expected_attributes.find(e.first)->second),                  nostd::get<uint32_t>(e.second));      else if (e.first == "cost")        EXPECT_EQ(nostd::get<double>(expected_attributes.find(e.first)->second),                  nostd::get<double>(e.second));      else        EXPECT_EQ(opentelemetry::nostd::get<std::string>(expected_attributes.find(e.first)->second),                  opentelemetry::nostd::get<std::string>(e.second));    }  }  EXPECT_EQ(received_attributes.size(), expected_attributes.size());  // for missing service.name}TEST(ResourceTest, create_with_servicename){  ResourceAttributes expected_attributes = {      {"version", static_cast<uint32_t>(1)},      {"cost", 234.23},      {semconv::telemetry::kTelemetrySdkLanguage, "cpp"},      {semconv::telemetry::kTelemetrySdkName, "opentelemetry"},      {semconv::telemetry::kTelemetrySdkVersion, OPENTELEMETRY_SDK_VERSION},      {semconv::service::kServiceName, "backend"},  };  ResourceAttributes attributes = {      {"service.name", "backend"}, {"version", static_cast<uint32_t>(1)}, {"cost", 234.23}};  auto resource            = Resource::Create(attributes);  auto received_attributes = resource.GetAttributes();  for (auto &e : received_attributes)  {    EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());    if (expected_attributes.find(e.first) != expected_attributes.end())    {      if (e.first == "version")        EXPECT_EQ(nostd::get<uint32_t>(expected_attributes.find(e.first)->second),                  nostd::get<uint32_t>(e.second));      else if (e.first == "cost")        EXPECT_EQ(nostd::get<double>(expected_attributes.find(e.first)->second),                  nostd::get<double>(e.second));      else        EXPECT_EQ(nostd::get<std::string>(expected_attributes.find(e.first)->second),                  nostd::get<std::string>(e.second));    }  }  EXPECT_EQ(received_attributes.size(), expected_attributes.size());  // for missing service.name}TEST(ResourceTest, create_with_emptyatrributes){  ResourceAttributes expected_attributes = {      {semconv::telemetry::kTelemetrySdkLanguage, "cpp"},      {semconv::telemetry::kTelemetrySdkName, "opentelemetry"},      {semconv::telemetry::kTelemetrySdkVersion, OPENTELEMETRY_SDK_VERSION},      {semconv::service::kServiceName, "unknown_service"},  };  ResourceAttributes attributes = {};  auto resource                 = Resource::Create(attributes);  auto received_attributes      = resource.GetAttributes();  for (auto &e : received_attributes)  {    EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());    if (expected_attributes.find(e.first) != expected_attributes.end())    {      EXPECT_EQ(opentelemetry::nostd::get<std::string>(expected_attributes.find(e.first)->second),                opentelemetry::nostd::get<std::string>(e.second));    }  }  EXPECT_EQ(received_attributes.size(), expected_attributes.size());  // for missing service.name}TEST(ResourceTest, create_with_schemaurl){  const std::string schema_url    = "https://opentelemetry.io/schemas/1.2.0";  ResourceAttributes attributes   = {};  auto resource                   = Resource::Create(attributes, schema_url);  const auto &received_schema_url = resource.GetSchemaURL();  EXPECT_EQ(received_schema_url, schema_url);}TEST(ResourceTest, Merge){  TestResource resource1(ResourceAttributes({{"service", "backend"}}));  TestResource resource2(ResourceAttributes({{"host", "service-host"}}));  std::map<std::string, std::string> expected_attributes = {{"service", "backend"},                                                            {"host", "service-host"}};  auto merged_resource     = resource1.Merge(resource2);  auto received_attributes = merged_resource.GetAttributes();  for (auto &e : received_attributes)  {    EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());    if (expected_attributes.find(e.first) != expected_attributes.end())    {      EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));    }  }  EXPECT_EQ(received_attributes.size(), expected_attributes.size());}TEST(ResourceTest, MergeEmptyString){  TestResource resource1({{"service", "backend"}, {"host", "service-host"}});  TestResource resource2({{"service", ""}, {"host", "another-service-host"}});  std::map<std::string, std::string> expected_attributes = {{"service", ""},                                                            {"host", "another-service-host"}};  auto merged_resource     = resource1.Merge(resource2);  auto received_attributes = merged_resource.GetAttributes();  for (auto &e : received_attributes)  {    EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());    if (expected_attributes.find(e.first) != expected_attributes.end())    {      EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));    }  }  EXPECT_EQ(received_attributes.size(), expected_attributes.size());}TEST(ResourceTest, MergeSchemaUrl){  const std::string url = "https://opentelemetry.io/schemas/v3.1.4";  TestResource resource_empty_url({}, "");  TestResource resource_some_url({}, url);  TestResource resource_different_url({}, "different");  // Specified behavior:  auto merged_both_empty = resource_empty_url.Merge(resource_empty_url);  EXPECT_TRUE(merged_both_empty.GetSchemaURL().empty());  auto merged_old_empty = resource_empty_url.Merge(resource_some_url);  EXPECT_EQ(merged_old_empty.GetSchemaURL(), url);  auto merged_updating_empty = resource_some_url.Merge(resource_empty_url);  EXPECT_EQ(merged_updating_empty.GetSchemaURL(), url);  auto merged_same_url = resource_some_url.Merge(resource_some_url);  EXPECT_EQ(merged_same_url.GetSchemaURL(), url);  // Implementation-defined behavior:  auto merged_different_url = resource_different_url.Merge(resource_some_url);  EXPECT_EQ(merged_different_url.GetSchemaURL(), url);}#ifndef NO_GETENVTEST(ResourceTest, OtelResourceDetector){  std::map<std::string, std::string> expected_attributes = {{"k", "v"}};  setenv("OTEL_RESOURCE_ATTRIBUTES", "k=v", 1);  OTELResourceDetector detector;  auto resource            = detector.Detect();  auto received_attributes = resource.GetAttributes();  for (auto &e : received_attributes)  {    EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());    if (expected_attributes.find(e.first) != expected_attributes.end())    {      EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));    }  }  EXPECT_EQ(received_attributes.size(), expected_attributes.size());  unsetenv("OTEL_RESOURCE_ATTRIBUTES");}TEST(ResourceTest, OtelResourceDetectorServiceNameOverride){  std::map<std::string, std::string> expected_attributes = {{"service.name", "new_name"}};  setenv("OTEL_RESOURCE_ATTRIBUTES", "service.name=old_name", 1);  setenv("OTEL_SERVICE_NAME", "new_name", 1);  OTELResourceDetector detector;  auto resource            = detector.Detect();  auto received_attributes = resource.GetAttributes();  for (auto &e : received_attributes)  {    EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());    if (expected_attributes.find(e.first) != expected_attributes.end())    {      EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));    }  }  EXPECT_EQ(received_attributes.size(), expected_attributes.size());  unsetenv("OTEL_SERVICE_NAME");  unsetenv("OTEL_RESOURCE_ATTRIBUTES");}TEST(ResourceTest, OtelResourceDetectorEmptyEnv){  std::map<std::string, std::string> expected_attributes = {};  unsetenv("OTEL_RESOURCE_ATTRIBUTES");  OTELResourceDetector detector;  auto resource            = detector.Detect();  auto received_attributes = resource.GetAttributes();  for (auto &e : received_attributes)  {    EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());    if (expected_attributes.find(e.first) != expected_attributes.end())    {      EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));    }  }  EXPECT_EQ(received_attributes.size(), expected_attributes.size());}#endifTEST(ResourceTest, DerivedResourceDetector){  TestResourceDetector detector;  detector.attributes            = {{"key", "value"}};  detector.schema_url            = "https://opentelemetry.io/schemas/v3.1.4";  const auto resource            = detector.Detect();  const auto received_attributes = resource.GetAttributes();  EXPECT_EQ(received_attributes.size(), 1);  EXPECT_EQ(resource.GetSchemaURL(), detector.schema_url);  EXPECT_TRUE(received_attributes.find("key") != received_attributes.end());}
 |