aboutsummaryrefslogtreecommitdiff
path: root/third_party/abseil-cpp/absl/strings/internal/cordz_sample_token_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/abseil-cpp/absl/strings/internal/cordz_sample_token_test.cc')
-rw-r--r--third_party/abseil-cpp/absl/strings/internal/cordz_sample_token_test.cc208
1 files changed, 208 insertions, 0 deletions
diff --git a/third_party/abseil-cpp/absl/strings/internal/cordz_sample_token_test.cc b/third_party/abseil-cpp/absl/strings/internal/cordz_sample_token_test.cc
new file mode 100644
index 0000000000..9f54301d68
--- /dev/null
+++ b/third_party/abseil-cpp/absl/strings/internal/cordz_sample_token_test.cc
@@ -0,0 +1,208 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/cordz_sample_token.h"
+
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/memory/memory.h"
+#include "absl/random/random.h"
+#include "absl/strings/cordz_test_helpers.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+#include "absl/strings/internal/cordz_handle.h"
+#include "absl/strings/internal/cordz_info.h"
+#include "absl/synchronization/internal/thread_pool.h"
+#include "absl/synchronization/notification.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Eq;
+using ::testing::Ne;
+
+// Used test values
+auto constexpr kTrackCordMethod = CordzUpdateTracker::kConstructorString;
+
+TEST(CordzSampleTokenTest, IteratorTraits) {
+ static_assert(std::is_copy_constructible<CordzSampleToken::Iterator>::value,
+ "");
+ static_assert(std::is_copy_assignable<CordzSampleToken::Iterator>::value, "");
+ static_assert(std::is_move_constructible<CordzSampleToken::Iterator>::value,
+ "");
+ static_assert(std::is_move_assignable<CordzSampleToken::Iterator>::value, "");
+ static_assert(
+ std::is_same<
+ std::iterator_traits<CordzSampleToken::Iterator>::iterator_category,
+ std::input_iterator_tag>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<CordzSampleToken::Iterator>::value_type,
+ const CordzInfo&>::value,
+ "");
+ static_assert(
+ std::is_same<
+ std::iterator_traits<CordzSampleToken::Iterator>::difference_type,
+ ptrdiff_t>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<CordzSampleToken::Iterator>::pointer,
+ const CordzInfo*>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<CordzSampleToken::Iterator>::reference,
+ const CordzInfo&>::value,
+ "");
+}
+
+TEST(CordzSampleTokenTest, IteratorEmpty) {
+ CordzSampleToken token;
+ EXPECT_THAT(token.begin(), Eq(token.end()));
+}
+
+TEST(CordzSampleTokenTest, Iterator) {
+ TestCordData cord1, cord2, cord3;
+ CordzInfo::TrackCord(cord1.data, kTrackCordMethod);
+ CordzInfo* info1 = cord1.data.cordz_info();
+ CordzInfo::TrackCord(cord2.data, kTrackCordMethod);
+ CordzInfo* info2 = cord2.data.cordz_info();
+ CordzInfo::TrackCord(cord3.data, kTrackCordMethod);
+ CordzInfo* info3 = cord3.data.cordz_info();
+
+ CordzSampleToken token;
+ std::vector<const CordzInfo*> found;
+ for (const CordzInfo& cord_info : token) {
+ found.push_back(&cord_info);
+ }
+
+ EXPECT_THAT(found, ElementsAre(info3, info2, info1));
+
+ info1->Untrack();
+ info2->Untrack();
+ info3->Untrack();
+}
+
+TEST(CordzSampleTokenTest, IteratorEquality) {
+ TestCordData cord1;
+ TestCordData cord2;
+ TestCordData cord3;
+ CordzInfo::TrackCord(cord1.data, kTrackCordMethod);
+ CordzInfo* info1 = cord1.data.cordz_info();
+
+ CordzSampleToken token1;
+ // lhs starts with the CordzInfo corresponding to cord1 at the head.
+ CordzSampleToken::Iterator lhs = token1.begin();
+
+ CordzInfo::TrackCord(cord2.data, kTrackCordMethod);
+ CordzInfo* info2 = cord2.data.cordz_info();
+
+ CordzSampleToken token2;
+ // rhs starts with the CordzInfo corresponding to cord2 at the head.
+ CordzSampleToken::Iterator rhs = token2.begin();
+
+ CordzInfo::TrackCord(cord3.data, kTrackCordMethod);
+ CordzInfo* info3 = cord3.data.cordz_info();
+
+ // lhs is on cord1 while rhs is on cord2.
+ EXPECT_THAT(lhs, Ne(rhs));
+
+ rhs++;
+ // lhs and rhs are both on cord1, but they didn't come from the same
+ // CordzSampleToken.
+ EXPECT_THAT(lhs, Ne(rhs));
+
+ lhs++;
+ rhs++;
+ // Both lhs and rhs are done, so they are on nullptr.
+ EXPECT_THAT(lhs, Eq(rhs));
+
+ info1->Untrack();
+ info2->Untrack();
+ info3->Untrack();
+}
+
+TEST(CordzSampleTokenTest, MultiThreaded) {
+ Notification stop;
+ static constexpr int kNumThreads = 4;
+ static constexpr int kNumCords = 3;
+ static constexpr int kNumTokens = 3;
+ absl::synchronization_internal::ThreadPool pool(kNumThreads);
+
+ for (int i = 0; i < kNumThreads; ++i) {
+ pool.Schedule([&stop]() {
+ absl::BitGen gen;
+ TestCordData cords[kNumCords];
+ std::unique_ptr<CordzSampleToken> tokens[kNumTokens];
+
+ while (!stop.HasBeenNotified()) {
+ // Randomly perform one of five actions:
+ // 1) Untrack
+ // 2) Track
+ // 3) Iterate over Cords visible to a token.
+ // 4) Unsample
+ // 5) Sample
+ int index = absl::Uniform(gen, 0, kNumCords);
+ if (absl::Bernoulli(gen, 0.5)) {
+ TestCordData& cord = cords[index];
+ // Track/untrack.
+ if (cord.data.is_profiled()) {
+ // 1) Untrack
+ cord.data.cordz_info()->Untrack();
+ cord.data.clear_cordz_info();;
+ } else {
+ // 2) Track
+ CordzInfo::TrackCord(cord.data, kTrackCordMethod);
+ }
+ } else {
+ std::unique_ptr<CordzSampleToken>& token = tokens[index];
+ if (token) {
+ if (absl::Bernoulli(gen, 0.5)) {
+ // 3) Iterate over Cords visible to a token.
+ for (const CordzInfo& info : *token) {
+ // This is trivial work to allow us to compile the loop.
+ EXPECT_THAT(info.Next(*token), Ne(&info));
+ }
+ } else {
+ // 4) Unsample
+ token = nullptr;
+ }
+ } else {
+ // 5) Sample
+ token = absl::make_unique<CordzSampleToken>();
+ }
+ }
+ }
+ for (TestCordData& cord : cords) {
+ CordzInfo::MaybeUntrackCord(cord.data.cordz_info());
+ }
+ });
+ }
+ // The threads will hammer away. Give it a little bit of time for tsan to
+ // spot errors.
+ absl::SleepFor(absl::Seconds(3));
+ stop.Notify();
+}
+
+} // namespace
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace absl