diff options
Diffstat (limited to 'src/jaegertracing/opentelemetry-cpp/sdk/test/common')
16 files changed, 1011 insertions, 0 deletions
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/BUILD new file mode 100644 index 000000000..91d56996f --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/BUILD @@ -0,0 +1,153 @@ +load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") + +cc_test( + name = "random_test", + srcs = [ + "random_test.cc", + ], + tags = ["test"], + deps = [ + "//sdk/src/common:random", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "fast_random_number_generator_test", + srcs = [ + "fast_random_number_generator_test.cc", + ], + tags = ["test"], + deps = [ + "//sdk/src/common:random", + "@com_google_googletest//:gtest_main", + ], +) + +otel_cc_benchmark( + name = "random_benchmark", + srcs = ["random_benchmark.cc"], + tags = ["test"], + deps = ["//sdk/src/common:random"], +) + +cc_test( + name = "atomic_unique_ptr_test", + srcs = [ + "atomic_unique_ptr_test.cc", + ], + tags = ["test"], + deps = [ + "//api", + "//sdk:headers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "circular_buffer_range_test", + srcs = [ + "circular_buffer_range_test.cc", + ], + tags = ["test"], + deps = [ + "//api", + "//sdk:headers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "random_fork_test", + srcs = [ + "random_fork_test.cc", + ], + tags = ["test"], + deps = [ + "//sdk/src/common:random", + ], +) + +cc_library( + name = "baseline_circular_buffer", + hdrs = [ + "baseline_circular_buffer.h", + ], + include_prefix = "test/common", + deps = [ + "//api", + ], +) + +otel_cc_benchmark( + name = "circular_buffer_benchmark", + srcs = ["circular_buffer_benchmark.cc"], + tags = ["test"], + deps = [ + ":baseline_circular_buffer", + "//sdk:headers", + ], +) + +cc_test( + name = "empty_attributes_test", + srcs = [ + "empty_attributes_test.cc", + ], + tags = ["test"], + deps = [ + "//api", + "//sdk:headers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "attribute_utils_test", + srcs = [ + "attribute_utils_test.cc", + ], + tags = ["test"], + deps = [ + "//api", + "//sdk:headers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "global_log_handle_test", + srcs = [ + "global_log_handle_test.cc", + ], + tags = ["test"], + deps = [ + "//api", + "//sdk:headers", + "//sdk/src/common:global_log_handler", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "attributemap_hash_test", + srcs = [ + "attributemap_hash_test.cc", + ], + tags = ["test"], + deps = [ + "//api", + "//sdk:headers", + "@com_google_googletest//:gtest_main", + ], +) + +otel_cc_benchmark( + name = "attributemap_hash_benchmark", + srcs = ["attributemap_hash_benchmark.cc"], + tags = ["test"], + deps = [ + "//api", + "//sdk:headers", + ], +) diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/CMakeLists.txt new file mode 100644 index 000000000..0fefc86b1 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/CMakeLists.txt @@ -0,0 +1,37 @@ +foreach( + testname + random_test + fast_random_number_generator_test + atomic_unique_ptr_test + circular_buffer_range_test + circular_buffer_test + attribute_utils_test + attributemap_hash_test + global_log_handle_test) + + add_executable(${testname} "${testname}.cc") + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_common opentelemetry_trace) + + gtest_add_tests( + TARGET ${testname} + TEST_PREFIX trace. + TEST_LIST ${testname}) +endforeach() + +add_executable(random_fork_test random_fork_test.cc) +target_link_libraries(random_fork_test opentelemetry_common) +add_test(random_fork_test random_fork_test) + +add_executable(random_benchmark random_benchmark.cc) +target_link_libraries(random_benchmark benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common) + +add_executable(circular_buffer_benchmark circular_buffer_benchmark.cc) +target_link_libraries(circular_buffer_benchmark benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + +add_executable(attributemap_hash_benchmark attributemap_hash_benchmark.cc) +target_link_libraries(attributemap_hash_benchmark benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common) diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/atomic_unique_ptr_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/atomic_unique_ptr_test.cc new file mode 100644 index 000000000..aa6d88a00 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/atomic_unique_ptr_test.cc @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/atomic_unique_ptr.h" + +#include <gtest/gtest.h> +using opentelemetry::sdk::common::AtomicUniquePtr; + +TEST(AtomicUniquePtrTest, SwapIfNullWithNull) +{ + AtomicUniquePtr<int> ptr; + EXPECT_TRUE(ptr.IsNull()); + + std::unique_ptr<int> x{new int{33}}; + EXPECT_TRUE(ptr.SwapIfNull(x)); + EXPECT_EQ(x, nullptr); +} + +TEST(AtomicUniquePtrTest, SwapIfNullWithNonNull) +{ + AtomicUniquePtr<int> ptr; + ptr.Reset(new int{11}); + std::unique_ptr<int> x{new int{33}}; + EXPECT_TRUE(!ptr.SwapIfNull(x)); + EXPECT_NE(x, nullptr); + EXPECT_EQ(*x, 33); + EXPECT_EQ(*ptr, 11); +} + +TEST(AtomicUniquePtrTest, Swap) +{ + AtomicUniquePtr<int> ptr; + EXPECT_TRUE(ptr.IsNull()); + + ptr.Reset(new int{11}); + std::unique_ptr<int> x{new int{33}}; + ptr.Swap(x); + EXPECT_FALSE(ptr.IsNull()); + EXPECT_NE(x, nullptr); + EXPECT_EQ(*x, 11); + EXPECT_EQ(*ptr, 33); +} diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attribute_utils_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attribute_utils_test.cc new file mode 100644 index 000000000..b7ef17244 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attribute_utils_test.cc @@ -0,0 +1,53 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/attribute_utils.h" + +#include <gtest/gtest.h> + +TEST(AttributeMapTest, DefaultConstruction) +{ + + opentelemetry::sdk::common::AttributeMap attribute_map; + EXPECT_EQ(attribute_map.GetAttributes().size(), 0); +} + +TEST(OrderedAttributeMapTest, DefaultConstruction) +{ + opentelemetry::sdk::common::OrderedAttributeMap attribute_map; + EXPECT_EQ(attribute_map.GetAttributes().size(), 0); +} + +TEST(AttributeMapTest, AttributesConstruction) +{ + const int kNumAttributes = 3; + std::string keys[kNumAttributes] = {"attr1", "attr2", "attr3"}; + int values[kNumAttributes] = {15, 24, 37}; + std::map<std::string, int> attributes = { + {keys[0], values[0]}, {keys[1], values[1]}, {keys[2], values[2]}}; + + opentelemetry::common::KeyValueIterableView<std::map<std::string, int>> iterable(attributes); + opentelemetry::sdk::common::AttributeMap attribute_map(iterable); + + for (int i = 0; i < kNumAttributes; i++) + { + EXPECT_EQ(opentelemetry::nostd::get<int>(attribute_map.GetAttributes().at(keys[i])), values[i]); + } +} + +TEST(OrderedAttributeMapTest, AttributesConstruction) +{ + const int kNumAttributes = 3; + std::string keys[kNumAttributes] = {"attr1", "attr2", "attr3"}; + int values[kNumAttributes] = {15, 24, 37}; + std::map<std::string, int> attributes = { + {keys[0], values[0]}, {keys[1], values[1]}, {keys[2], values[2]}}; + + opentelemetry::common::KeyValueIterableView<std::map<std::string, int>> iterable(attributes); + opentelemetry::sdk::common::OrderedAttributeMap attribute_map(iterable); + + for (int i = 0; i < kNumAttributes; i++) + { + EXPECT_EQ(opentelemetry::nostd::get<int>(attribute_map.GetAttributes().at(keys[i])), values[i]); + } +} diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_benchmark.cc new file mode 100644 index 000000000..811ecb23d --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_benchmark.cc @@ -0,0 +1,22 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include <benchmark/benchmark.h> +#include "opentelemetry/sdk/common/attributemap_hash.h" + +using namespace opentelemetry::sdk::common; +namespace +{ +void BM_AttributeMapHash(benchmark::State &state) +{ + OrderedAttributeMap map1 = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}, {"k4", "v4"}, + {"k5", true}, {"k6", 12}, {"k7", 12.209}}; + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(GetHashForAttributeMap(map1)); + } +} +BENCHMARK(BM_AttributeMapHash); + +} // namespace +BENCHMARK_MAIN(); diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_test.cc new file mode 100644 index 000000000..7d2748670 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_test.cc @@ -0,0 +1,32 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/attributemap_hash.h" +#include <gtest/gtest.h> + +using namespace opentelemetry::sdk::common; +TEST(AttributeMapHashTest, BasicTests) +{ + { + OrderedAttributeMap map1 = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}}; + OrderedAttributeMap map2 = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}, {"k4", "v4"}}; + OrderedAttributeMap map3 = {{"k3", "v3"}, {"k1", "v1"}, {"k2", "v2"}}; + + EXPECT_TRUE(GetHashForAttributeMap(map1) != 0); + EXPECT_TRUE(GetHashForAttributeMap(map1) == GetHashForAttributeMap(map1)); + EXPECT_TRUE(GetHashForAttributeMap(map1) != GetHashForAttributeMap(map2)); + EXPECT_TRUE(GetHashForAttributeMap(map1) == GetHashForAttributeMap(map3)); + } + + { + OrderedAttributeMap map1 = {{"k1", 10}, {"k2", true}, {"k3", 12.22}}; + OrderedAttributeMap map2 = {{"k3", 12.22}, {"k1", 10}, {"k2", true}}; + EXPECT_TRUE(GetHashForAttributeMap(map1) == GetHashForAttributeMap(map2)); + EXPECT_TRUE(GetHashForAttributeMap(map1) != 0); + } + + { + OrderedAttributeMap map1 = {}; + EXPECT_TRUE(GetHashForAttributeMap(map1) == 0); + } +}
\ No newline at end of file diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/baseline_circular_buffer.h b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/baseline_circular_buffer.h new file mode 100644 index 000000000..398a4d038 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/baseline_circular_buffer.h @@ -0,0 +1,88 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <cstdint> +#include <memory> +#include <mutex> +#include <vector> + +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace testing +{ +/** + * A locking circular buffer. + * + * Used as a baseline in benchmarking. + */ +template <class T> +class BaselineCircularBuffer +{ +public: + explicit BaselineCircularBuffer(size_t max_size) : data_{max_size} {} + + /** + * Add an element to the circular buffer. + * @param element the element to add + * @return true if the element was added successfully + */ + bool Add(std::unique_ptr<T> &element) noexcept { return this->Add(std::move(element)); } + + bool Add(std::unique_ptr<T> &&element) noexcept + { + std::lock_guard<std::mutex> lock_guard{mutex_}; + if (tail_ + data_.size() == head_) + { + return false; + } + data_[head_ % data_.size()] = std::move(element); + head_ += 1; + return true; + } + + /** + * Consume elements in the circular buffer. + * @param f the callback to call for each element + */ + template <class F> + void Consume(F f) noexcept + { + std::lock_guard<std::mutex> lock_guard{mutex_}; + if (head_ == tail_) + { + return; + } + auto tail_index = tail_ % data_.size(); + auto head_index = head_ % data_.size(); + if (tail_index < head_index) + { + for (auto i = tail_index; i < head_index; ++i) + { + f(std::move(data_[i])); + } + } + else + { + for (auto i = tail_index; i < data_.size(); ++i) + { + f(std::move(data_[i])); + } + for (auto i = 0ull; i < head_index; ++i) + { + f(std::move(data_[i])); + } + } + tail_ = head_; + } + +private: + std::mutex mutex_; + uint64_t head_{0}; + uint64_t tail_{0}; + std::vector<std::unique_ptr<T>> data_; +}; +} // namespace testing +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_benchmark.cc new file mode 100644 index 000000000..1f2b9b42c --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_benchmark.cc @@ -0,0 +1,133 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "benchmark/benchmark.h" + +#include <atomic> +#include <cstdint> +#include <iostream> +#include <memory> +#include <random> +#include <thread> +#include <vector> + +#include "opentelemetry/sdk/common/circular_buffer.h" +#include "test/common/baseline_circular_buffer.h" +using opentelemetry::sdk::common::AtomicUniquePtr; +using opentelemetry::sdk::common::CircularBuffer; +using opentelemetry::sdk::common::CircularBufferRange; +using opentelemetry::testing::BaselineCircularBuffer; + +const int N = 10000; + +static uint64_t ConsumeBufferNumbers(BaselineCircularBuffer<uint64_t> &buffer) noexcept +{ + uint64_t result = 0; + buffer.Consume([&](std::unique_ptr<uint64_t> &&x) { + result += *x; + x.reset(); + }); + return result; +} + +static uint64_t ConsumeBufferNumbers(CircularBuffer<uint64_t> &buffer) noexcept +{ + uint64_t result = 0; + buffer.Consume(buffer.size(), + [&](CircularBufferRange<AtomicUniquePtr<uint64_t>> &range) noexcept { + range.ForEach([&](AtomicUniquePtr<uint64_t> &ptr) noexcept { + result += *ptr; + ptr.Reset(); + return true; + }); + }); + return result; +} + +template <class Buffer> +static void GenerateNumbersForThread(Buffer &buffer, int n, std::atomic<uint64_t> &sum) noexcept +{ + thread_local std::mt19937_64 random_number_generator{std::random_device{}()}; + for (int i = 0; i < n; ++i) + { + auto x = random_number_generator(); + std::unique_ptr<uint64_t> element{new uint64_t{x}}; + if (buffer.Add(element)) + { + sum += x; + } + } +} + +template <class Buffer> +static uint64_t GenerateNumbers(Buffer &buffer, int num_threads, int n) noexcept +{ + std::atomic<uint64_t> sum{0}; + std::vector<std::thread> threads(num_threads); + for (auto &thread : threads) + { + thread = std::thread{GenerateNumbersForThread<Buffer>, std::ref(buffer), n, std::ref(sum)}; + } + for (auto &thread : threads) + { + thread.join(); + } + return sum; +} + +template <class Buffer> +static void ConsumeNumbers(Buffer &buffer, uint64_t &sum, std::atomic<bool> &finished) noexcept +{ + while (!finished) + { + sum += ConsumeBufferNumbers(buffer); + } + sum += ConsumeBufferNumbers(buffer); +} + +template <class Buffer> +static void RunSimulation(Buffer &buffer, int num_threads, int n) noexcept +{ + std::atomic<bool> finished{false}; + uint64_t consumer_sum{0}; + std::thread consumer_thread{ConsumeNumbers<Buffer>, std::ref(buffer), std::ref(consumer_sum), + std::ref(finished)}; + uint64_t producer_sum = GenerateNumbers(buffer, num_threads, n); + finished = true; + consumer_thread.join(); + if (consumer_sum != producer_sum) + { + std::cerr << "Sumulation failed: consumer_sum != producer_sum\n"; + std::terminate(); + } +} + +static void BM_BaselineBuffer(benchmark::State &state) +{ + const size_t max_elements = 500; + const int num_threads = static_cast<int>(state.range(0)); + const int n = static_cast<int>(N / num_threads); + BaselineCircularBuffer<uint64_t> buffer{max_elements}; + for (auto _ : state) + { + RunSimulation(buffer, num_threads, n); + } +} + +BENCHMARK(BM_BaselineBuffer)->Arg(1)->Arg(2)->Arg(4); + +static void BM_LockFreeBuffer(benchmark::State &state) +{ + const size_t max_elements = 500; + const int num_threads = static_cast<int>(state.range(0)); + const int n = static_cast<int>(N / num_threads); + CircularBuffer<uint64_t> buffer{max_elements}; + for (auto _ : state) + { + RunSimulation(buffer, num_threads, n); + } +} + +BENCHMARK(BM_LockFreeBuffer)->Arg(1)->Arg(2)->Arg(4); + +BENCHMARK_MAIN(); diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_range_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_range_test.cc new file mode 100644 index 000000000..585270468 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_range_test.cc @@ -0,0 +1,59 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/circular_buffer_range.h" + +#include <iterator> + +#include <gtest/gtest.h> +using opentelemetry::sdk::common::CircularBufferRange; + +TEST(CircularBufferRangeTest, ForEach) +{ + int array1[] = {1, 2, 3, 4}; + int array2[] = {5, 6, 7}; + CircularBufferRange<int> range{array1, array2}; + + int x = 0; + range.ForEach([&](int y) { + EXPECT_EQ(++x, y); + return true; + }); + EXPECT_EQ(x, 7); +} + +TEST(CircularBufferRangeTest, ForEachWithExit) +{ + int array1[] = {1, 2, 3, 4}; + int array2[] = {5, 6, 7}; + CircularBufferRange<int> range{array1, array2}; + + int x = 0; + range.ForEach([&](int y) { + EXPECT_EQ(++x, y); + return false; + }); + EXPECT_EQ(x, 1); + + x = 0; + range.ForEach([&](int y) { + EXPECT_EQ(++x, y); + return y != 5; + }); + EXPECT_EQ(x, 5); +} + +TEST(CircularBufferRangeTest, Conversion) +{ + int array1[] = {1, 2, 3, 4}; + int array2[] = {5, 6, 7}; + CircularBufferRange<int> range{array1, array2}; + + CircularBufferRange<const int> range2{range}; + int x = 0; + range2.ForEach([&](int y) { + EXPECT_EQ(++x, y); + return true; + }); + EXPECT_EQ(x, 7); +} diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_test.cc new file mode 100644 index 000000000..a20c3e42a --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_test.cc @@ -0,0 +1,161 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/circular_buffer.h" + +#include <algorithm> +#include <cassert> +#include <random> +#include <thread> + +#include <gtest/gtest.h> +using opentelemetry::sdk::common::AtomicUniquePtr; +using opentelemetry::sdk::common::CircularBuffer; +using opentelemetry::sdk::common::CircularBufferRange; + +static thread_local std::mt19937 RandomNumberGenerator{std::random_device{}()}; + +static void GenerateRandomNumbers(CircularBuffer<uint32_t> &buffer, + std::vector<uint32_t> &numbers, + int n) +{ + for (int i = 0; i < n; ++i) + { + auto value = static_cast<uint32_t>(RandomNumberGenerator()); + std::unique_ptr<uint32_t> x{new uint32_t{value}}; + if (buffer.Add(x)) + { + numbers.push_back(value); + } + } +} + +static void RunNumberProducers(CircularBuffer<uint32_t> &buffer, + std::vector<uint32_t> &numbers, + int num_threads, + int n) +{ + std::vector<std::vector<uint32_t>> thread_numbers(num_threads); + std::vector<std::thread> threads(num_threads); + for (int thread_index = 0; thread_index < num_threads; ++thread_index) + { + threads[thread_index] = std::thread{GenerateRandomNumbers, std::ref(buffer), + std::ref(thread_numbers[thread_index]), n}; + } + for (auto &thread : threads) + { + thread.join(); + } + for (int thread_index = 0; thread_index < num_threads; ++thread_index) + { + numbers.insert(numbers.end(), thread_numbers[thread_index].begin(), + thread_numbers[thread_index].end()); + } +} + +void RunNumberConsumer(CircularBuffer<uint32_t> &buffer, + std::atomic<bool> &exit, + std::vector<uint32_t> &numbers) +{ + while (true) + { + if (exit && buffer.Peek().empty()) + { + return; + } + auto n = std::uniform_int_distribution<size_t>{0, buffer.Peek().size()}(RandomNumberGenerator); + buffer.Consume(n, [&](CircularBufferRange<AtomicUniquePtr<uint32_t>> range) noexcept { + assert(range.size() == n); + range.ForEach([&](AtomicUniquePtr<uint32_t> &ptr) noexcept { + assert(!ptr.IsNull()); + numbers.push_back(*ptr); + ptr.Reset(); + return true; + }); + }); + } +} + +TEST(CircularBufferTest, Add) +{ + CircularBuffer<int> buffer{10}; + + std::unique_ptr<int> x{new int{11}}; + EXPECT_TRUE(buffer.Add(x)); + EXPECT_EQ(x, nullptr); + auto range = buffer.Peek(); + EXPECT_EQ(range.size(), 1); + range.ForEach([](const AtomicUniquePtr<int> &y) { + EXPECT_EQ(*y, 11); + return true; + }); +} + +TEST(CircularBufferTest, Clear) +{ + CircularBuffer<int> buffer{10}; + + std::unique_ptr<int> x{new int{11}}; + EXPECT_TRUE(buffer.Add(x)); + EXPECT_EQ(x, nullptr); + buffer.Clear(); + EXPECT_TRUE(buffer.empty()); +} + +TEST(CircularBufferTest, AddOnFull) +{ + CircularBuffer<int> buffer{10}; + for (int i = 0; i < static_cast<int>(buffer.max_size()); ++i) + { + std::unique_ptr<int> x{new int{i}}; + EXPECT_TRUE(buffer.Add(x)); + } + std::unique_ptr<int> x{new int{33}}; + EXPECT_FALSE(buffer.Add(x)); + EXPECT_NE(x, nullptr); + EXPECT_EQ(*x, 33); +} + +TEST(CircularBufferTest, Consume) +{ + CircularBuffer<int> buffer{10}; + for (int i = 0; i < static_cast<int>(buffer.max_size()); ++i) + { + std::unique_ptr<int> x{new int{i}}; + EXPECT_TRUE(buffer.Add(x)); + } + int count = 0; + buffer.Consume(5, [&](CircularBufferRange<AtomicUniquePtr<int>> range) noexcept { + range.ForEach([&](AtomicUniquePtr<int> &ptr) { + EXPECT_EQ(*ptr, count++); + ptr.Reset(); + return true; + }); + }); + EXPECT_EQ(count, 5); +} + +TEST(CircularBufferTest, Simulation) +{ + const int num_producer_threads = 4; + const int n = 25000; + for (size_t max_size : {1, 2, 10, 50, 100, 1000}) + { + CircularBuffer<uint32_t> buffer{max_size}; + std::vector<uint32_t> producer_numbers; + std::vector<uint32_t> consumer_numbers; + auto producers = std::thread{RunNumberProducers, std::ref(buffer), std::ref(producer_numbers), + num_producer_threads, n}; + std::atomic<bool> exit{false}; + auto consumer = std::thread{RunNumberConsumer, std::ref(buffer), std::ref(exit), + std::ref(consumer_numbers)}; + producers.join(); + exit = true; + consumer.join(); + std::sort(producer_numbers.begin(), producer_numbers.end()); + std::sort(consumer_numbers.begin(), consumer_numbers.end()); + + EXPECT_EQ(producer_numbers.size(), consumer_numbers.size()); + EXPECT_EQ(producer_numbers, consumer_numbers); + } +} diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/empty_attributes_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/empty_attributes_test.cc new file mode 100644 index 000000000..f37ea0a5c --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/empty_attributes_test.cc @@ -0,0 +1,19 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/empty_attributes.h" + +#include <gtest/gtest.h> + +TEST(EmptyAttributesTest, TestSize) +{ + EXPECT_EQ(opentelemetry::sdk::GetEmptyAttributes().size(), 0); +} + +// Test that GetEmptyAttributes() always returns the same KeyValueIterableView +TEST(EmptyAttributesTest, TestMemory) +{ + auto attributes1 = opentelemetry::sdk::GetEmptyAttributes(); + auto attributes2 = opentelemetry::sdk::GetEmptyAttributes(); + EXPECT_EQ(memcmp(&attributes1, &attributes2, sizeof(attributes1)), 0); +} diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/fast_random_number_generator_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/fast_random_number_generator_test.cc new file mode 100644 index 000000000..e9209fdb6 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/fast_random_number_generator_test.cc @@ -0,0 +1,22 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "src/common/random.h" + +#include <random> + +#include <gtest/gtest.h> + +using opentelemetry::sdk::common::FastRandomNumberGenerator; + +TEST(FastRandomNumberGeneratorTest, GenerateUniqueNumbers) +{ + std::seed_seq seed_sequence{1, 2, 3}; + FastRandomNumberGenerator random_number_generator; + random_number_generator.seed(seed_sequence); + std::set<uint64_t> values; + for (int i = 0; i < 1000; ++i) + { + EXPECT_TRUE(values.insert(random_number_generator()).second); + } +} diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/global_log_handle_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/global_log_handle_test.cc new file mode 100644 index 000000000..a38bdc872 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/global_log_handle_test.cc @@ -0,0 +1,67 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/global_log_handler.h" + +#include <gtest/gtest.h> + +#include <cstring> + +class CustomLogHandler : public opentelemetry::sdk::common::internal_log::LogHandler +{ +public: + void Handle(opentelemetry::sdk::common::internal_log::LogLevel level, + const char *, + int, + const char *msg, + const opentelemetry::sdk::common::AttributeMap &) noexcept override + { + if (level == opentelemetry::sdk::common::internal_log::LogLevel::Debug) + { + EXPECT_EQ(0, strncmp(msg, "Debug message", 13)); + } + else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Error) + { + EXPECT_EQ(0, strncmp(msg, "Error message", 13)); + } + else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Info) + { + EXPECT_EQ(0, strncmp(msg, "Info message", 12)); + } + else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Warning) + { + EXPECT_EQ(0, strncmp(msg, "Warning message", 15)); + } + ++count; + } + + size_t count = 0; +}; + +TEST(GlobalLogHandleTest, CustomLogHandler) +{ + using opentelemetry::sdk::common::internal_log::LogHandler; + auto backup_log_handle = + opentelemetry::sdk::common::internal_log::GlobalLogHandler::GetLogHandler(); + auto backup_log_level = opentelemetry::sdk::common::internal_log::GlobalLogHandler::GetLogLevel(); + + auto custom_log_handler = opentelemetry::nostd::shared_ptr<LogHandler>(new CustomLogHandler{}); + opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogHandler(custom_log_handler); + auto before_count = static_cast<CustomLogHandler *>(custom_log_handler.get())->count; + opentelemetry::sdk::common::AttributeMap attributes = { + {"url", "https://opentelemetry.io/"}, {"content-length", 0}, {"content-type", "text/html"}}; + OTEL_INTERNAL_LOG_ERROR("Error message"); + OTEL_INTERNAL_LOG_DEBUG("Debug message. Headers:", attributes); + EXPECT_EQ(before_count + 1, static_cast<CustomLogHandler *>(custom_log_handler.get())->count); + + opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogLevel( + opentelemetry::sdk::common::internal_log::LogLevel::Debug); + OTEL_INTERNAL_LOG_ERROR("Error message"); + OTEL_INTERNAL_LOG_DEBUG("Debug message. Headers:", attributes); + OTEL_INTERNAL_LOG_INFO("Info message"); + OTEL_INTERNAL_LOG_WARN("Warning message"); + EXPECT_EQ(before_count + 5, static_cast<CustomLogHandler *>(custom_log_handler.get())->count); + + opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogHandler(backup_log_handle); + opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogLevel(backup_log_level); +} diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_benchmark.cc new file mode 100644 index 000000000..df2ebf95e --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_benchmark.cc @@ -0,0 +1,35 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "src/common/random.h" + +#include <cstdint> +#include <random> + +#include <benchmark/benchmark.h> + +namespace +{ +using opentelemetry::sdk::common::Random; + +void BM_RandomIdGeneration(benchmark::State &state) +{ + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(Random::GenerateRandom64()); + } +} +BENCHMARK(BM_RandomIdGeneration); + +void BM_RandomIdStdGeneration(benchmark::State &state) +{ + std::mt19937_64 generator{0}; + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(generator()); + } +} +BENCHMARK(BM_RandomIdStdGeneration); + +} // namespace +BENCHMARK_MAIN(); diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_fork_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_fork_test.cc new file mode 100644 index 000000000..2db8b9fcd --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_fork_test.cc @@ -0,0 +1,53 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef __unix__ +// Verifies that IDs don't clash after forking the process. +// +// See https://github.com/opentracing-contrib/nginx-opentracing/issues/52 +# include "src/common/random.h" + +# include <sys/mman.h> +# include <sys/types.h> +# include <sys/wait.h> +# include <unistd.h> +# include <cstdio> +# include <cstdlib> +# include <iostream> +using opentelemetry::sdk::common::Random; + +static uint64_t *child_id; + +int main() +{ + // Set up shared memory to communicate between parent and child processes. + // + // See https://stackoverflow.com/a/13274800/4447365 + child_id = static_cast<uint64_t *>( + mmap(nullptr, sizeof(*child_id), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)); + *child_id = 0; + if (fork() == 0) + { + *child_id = Random::GenerateRandom64(); + exit(EXIT_SUCCESS); + } + else + { + wait(nullptr); + auto parent_id = Random::GenerateRandom64(); + auto child_id_copy = *child_id; + munmap(static_cast<void *>(child_id), sizeof(*child_id)); + if (parent_id == child_id_copy) + { + std::cerr << "Child and parent ids are the same value " << parent_id << "\n"; + return -1; + } + } + return 0; +} +#else +int main() +{ + return 0; +} +#endif diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_test.cc new file mode 100644 index 000000000..35cfd4a1e --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_test.cc @@ -0,0 +1,35 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "src/common/random.h" + +#include <algorithm> +#include <iterator> + +#include <gtest/gtest.h> +using opentelemetry::sdk::common::Random; + +TEST(RandomTest, GenerateRandom64) +{ + EXPECT_NE(Random::GenerateRandom64(), Random::GenerateRandom64()); +} + +TEST(RandomTest, GenerateRandomBuffer) +{ + uint8_t buf1[8] = {0}; + uint8_t buf2[8] = {0}; + Random::GenerateRandomBuffer(buf1); + Random::GenerateRandomBuffer(buf2); + EXPECT_FALSE(std::equal(std::begin(buf1), std::end(buf1), std::begin(buf2))); + + // Edge cases. + for (auto size : {7, 8, 9, 16, 17}) + { + std::vector<uint8_t> buf1(size); + std::vector<uint8_t> buf2(size); + + Random::GenerateRandomBuffer(buf1); + Random::GenerateRandomBuffer(buf2); + EXPECT_FALSE(std::equal(std::begin(buf1), std::end(buf1), std::begin(buf2))); + } +} |