| Index: base/trace_event/trace_category_unittest.cc
|
| diff --git a/base/trace_event/trace_category_unittest.cc b/base/trace_event/trace_category_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6fc9bb3dc5d8d7b320ee39769486e0a9f5af124d
|
| --- /dev/null
|
| +++ b/base/trace_event/trace_category_unittest.cc
|
| @@ -0,0 +1,137 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <string.h>
|
| +
|
| +#include <memory>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/threading/thread.h"
|
| +#include "base/trace_event/category_registry.h"
|
| +#include "base/trace_event/trace_category.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace base {
|
| +namespace trace_event {
|
| +
|
| +// Static initializers are generally forbidden. However, in the past we ran in
|
| +// the case of some test using tracing in a static initializer. This test checks
|
| +// That the category registry doesn't rely on static initializers itself and is
|
| +// functional even if called from another static initializer.
|
| +bool Initializer() {
|
| + return CategoryRegistry::kCategoryMetadata &&
|
| + CategoryRegistry::kCategoryMetadata->is_valid();
|
| +}
|
| +bool g_initializer_check = Initializer();
|
| +
|
| +class TraceCategoryTest : public testing::Test {
|
| + public:
|
| + void SetUp() override { CategoryRegistry::Initialize(); }
|
| +
|
| + void TearDown() override { CategoryRegistry::ResetForTesting(); }
|
| +
|
| + static bool GetOrCreateCategoryByName(const char* name, TraceCategory** cat) {
|
| + return CategoryRegistry::GetOrCreateCategoryByName(name, cat);
|
| + };
|
| +
|
| + static CategoryRegistry::Range GetAllCategories() {
|
| + return CategoryRegistry::GetAllCategories();
|
| + }
|
| +
|
| + static void TestRaceThreadMain(WaitableEvent* event) {
|
| + TraceCategory* cat = nullptr;
|
| + event->Wait();
|
| + GetOrCreateCategoryByName("__test_race", &cat);
|
| + EXPECT_NE(nullptr, cat);
|
| + }
|
| +};
|
| +
|
| +TEST_F(TraceCategoryTest, Basic) {
|
| + ASSERT_NE(nullptr, CategoryRegistry::kCategoryMetadata);
|
| + ASSERT_TRUE(CategoryRegistry::kCategoryMetadata->is_valid());
|
| + ASSERT_FALSE(CategoryRegistry::kCategoryMetadata->is_enabled());
|
| +
|
| + // Metadata category is built-in and should create a new category.
|
| + TraceCategory* cat_meta = nullptr;
|
| + const char* kMetadataName = CategoryRegistry::kCategoryMetadata->name();
|
| + ASSERT_FALSE(GetOrCreateCategoryByName(kMetadataName, &cat_meta));
|
| + ASSERT_EQ(CategoryRegistry::kCategoryMetadata, cat_meta);
|
| +
|
| + TraceCategory* cat_1 = nullptr;
|
| + ASSERT_TRUE(GetOrCreateCategoryByName("__test_ab", &cat_1));
|
| + ASSERT_FALSE(cat_1->is_enabled());
|
| + ASSERT_EQ(0u, cat_1->enabled_filters());
|
| + cat_1->set_state_flag(TraceCategory::ENABLED_FOR_RECORDING);
|
| + cat_1->set_state_flag(TraceCategory::ENABLED_FOR_FILTERING);
|
| + ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING |
|
| + TraceCategory::ENABLED_FOR_FILTERING,
|
| + cat_1->state());
|
| +
|
| + cat_1->set_enabled_filters(129);
|
| + ASSERT_EQ(129u, cat_1->enabled_filters());
|
| + ASSERT_EQ(cat_1, CategoryRegistry::GetCategoryByStatePtr(cat_1->state_ptr()));
|
| +
|
| + cat_1->clear_state_flag(TraceCategory::ENABLED_FOR_FILTERING);
|
| + ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING, cat_1->state());
|
| + ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING, *cat_1->state_ptr());
|
| + ASSERT_TRUE(cat_1->is_enabled());
|
| +
|
| + TraceCategory* cat_2 = nullptr;
|
| + ASSERT_TRUE(GetOrCreateCategoryByName("__test_a", &cat_2));
|
| + ASSERT_FALSE(cat_2->is_enabled());
|
| + cat_2->set_state_flag(TraceCategory::ENABLED_FOR_RECORDING);
|
| +
|
| + TraceCategory* cat_2_copy = nullptr;
|
| + ASSERT_FALSE(GetOrCreateCategoryByName("__test_a", &cat_2_copy));
|
| + ASSERT_EQ(cat_2, cat_2_copy);
|
| +
|
| + TraceCategory* cat_3 = nullptr;
|
| + ASSERT_TRUE(GetOrCreateCategoryByName("__test_ab,__test_a", &cat_3));
|
| + ASSERT_FALSE(cat_3->is_enabled());
|
| + ASSERT_EQ(0u, cat_3->enabled_filters());
|
| +
|
| + int num_test_categories_seen = 0;
|
| + for (const TraceCategory& cat : GetAllCategories()) {
|
| + if (strcmp(cat.name(), kMetadataName) == 0)
|
| + ASSERT_TRUE(CategoryRegistry::IsBuiltinCategory(&cat));
|
| +
|
| + if (strncmp(cat.name(), "__test", 6) == 0) {
|
| + ASSERT_FALSE(CategoryRegistry::IsBuiltinCategory(&cat));
|
| + num_test_categories_seen++;
|
| + }
|
| + }
|
| + ASSERT_EQ(3, num_test_categories_seen);
|
| + ASSERT_TRUE(g_initializer_check);
|
| +}
|
| +
|
| +// Tries to cover the case of multiple threads creating the same category
|
| +// simultaeously. Should never end up with distinct entries with the same name.
|
| +TEST_F(TraceCategoryTest, ThreadRaces) {
|
| + const int kNumThreads = 32;
|
| + std::unique_ptr<Thread> threads[kNumThreads];
|
| + for (int i = 0; i < kNumThreads; i++) {
|
| + threads[i].reset(new Thread("test thread"));
|
| + threads[i]->Start();
|
| + }
|
| + WaitableEvent sync_event(WaitableEvent::ResetPolicy::MANUAL,
|
| + WaitableEvent::InitialState::NOT_SIGNALED);
|
| + for (int i = 0; i < kNumThreads; i++) {
|
| + threads[i]->task_runner()->PostTask(
|
| + FROM_HERE, Bind(&TestRaceThreadMain, Unretained(&sync_event)));
|
| + }
|
| + sync_event.Signal();
|
| + for (int i = 0; i < kNumThreads; i++)
|
| + threads[i]->Stop();
|
| +
|
| + int num_times_seen = 0;
|
| + for (const TraceCategory& cat : GetAllCategories()) {
|
| + if (strcmp(cat.name(), "__test_race") == 0)
|
| + num_times_seen++;
|
| + }
|
| + ASSERT_EQ(1, num_times_seen);
|
| +}
|
| +
|
| +} // namespace trace_event
|
| +} // namespace base
|
|
|