OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <string.h> |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/synchronization/waitable_event.h" |
| 11 #include "base/threading/thread.h" |
| 12 #include "base/trace_event/category_registry.h" |
| 13 #include "base/trace_event/trace_category.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" |
| 15 |
| 16 namespace base { |
| 17 namespace trace_event { |
| 18 |
| 19 // Static initializers are generally forbidden. However, in the past we ran in |
| 20 // the case of some test using tracing in a static initializer. This test checks |
| 21 // That the category registry doesn't rely on static initializers itself and is |
| 22 // functional even if called from another static initializer. |
| 23 bool Initializer() { |
| 24 return CategoryRegistry::kCategoryMetadata && |
| 25 CategoryRegistry::kCategoryMetadata->is_valid(); |
| 26 } |
| 27 bool g_initializer_check = Initializer(); |
| 28 |
| 29 class TraceCategoryTest : public testing::Test { |
| 30 public: |
| 31 void SetUp() override { CategoryRegistry::Initialize(); } |
| 32 |
| 33 void TearDown() override { CategoryRegistry::ResetForTesting(); } |
| 34 |
| 35 static bool GetOrCreateCategoryByName(const char* name, TraceCategory** cat) { |
| 36 return CategoryRegistry::GetOrCreateCategoryByName(name, cat); |
| 37 }; |
| 38 |
| 39 static CategoryRegistry::Range GetAllCategories() { |
| 40 return CategoryRegistry::GetAllCategories(); |
| 41 } |
| 42 |
| 43 static void TestRaceThreadMain(WaitableEvent* event) { |
| 44 TraceCategory* cat = nullptr; |
| 45 event->Wait(); |
| 46 GetOrCreateCategoryByName("__test_race", &cat); |
| 47 EXPECT_NE(nullptr, cat); |
| 48 } |
| 49 }; |
| 50 |
| 51 TEST_F(TraceCategoryTest, Basic) { |
| 52 ASSERT_NE(nullptr, CategoryRegistry::kCategoryMetadata); |
| 53 ASSERT_TRUE(CategoryRegistry::kCategoryMetadata->is_valid()); |
| 54 ASSERT_FALSE(CategoryRegistry::kCategoryMetadata->is_enabled()); |
| 55 |
| 56 // Metadata category is built-in and should create a new category. |
| 57 TraceCategory* cat_meta = nullptr; |
| 58 const char* kMetadataName = CategoryRegistry::kCategoryMetadata->name(); |
| 59 ASSERT_FALSE(GetOrCreateCategoryByName(kMetadataName, &cat_meta)); |
| 60 ASSERT_EQ(CategoryRegistry::kCategoryMetadata, cat_meta); |
| 61 |
| 62 TraceCategory* cat_1 = nullptr; |
| 63 ASSERT_TRUE(GetOrCreateCategoryByName("__test_ab", &cat_1)); |
| 64 ASSERT_FALSE(cat_1->is_enabled()); |
| 65 ASSERT_EQ(0u, cat_1->enabled_filters()); |
| 66 cat_1->set_state_flag(TraceCategory::ENABLED_FOR_RECORDING); |
| 67 cat_1->set_state_flag(TraceCategory::ENABLED_FOR_FILTERING); |
| 68 ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING | |
| 69 TraceCategory::ENABLED_FOR_FILTERING, |
| 70 cat_1->state()); |
| 71 |
| 72 cat_1->set_enabled_filters(129); |
| 73 ASSERT_EQ(129u, cat_1->enabled_filters()); |
| 74 ASSERT_EQ(cat_1, CategoryRegistry::GetCategoryByStatePtr(cat_1->state_ptr())); |
| 75 |
| 76 cat_1->clear_state_flag(TraceCategory::ENABLED_FOR_FILTERING); |
| 77 ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING, cat_1->state()); |
| 78 ASSERT_EQ(TraceCategory::ENABLED_FOR_RECORDING, *cat_1->state_ptr()); |
| 79 ASSERT_TRUE(cat_1->is_enabled()); |
| 80 |
| 81 TraceCategory* cat_2 = nullptr; |
| 82 ASSERT_TRUE(GetOrCreateCategoryByName("__test_a", &cat_2)); |
| 83 ASSERT_FALSE(cat_2->is_enabled()); |
| 84 cat_2->set_state_flag(TraceCategory::ENABLED_FOR_RECORDING); |
| 85 |
| 86 TraceCategory* cat_2_copy = nullptr; |
| 87 ASSERT_FALSE(GetOrCreateCategoryByName("__test_a", &cat_2_copy)); |
| 88 ASSERT_EQ(cat_2, cat_2_copy); |
| 89 |
| 90 TraceCategory* cat_3 = nullptr; |
| 91 ASSERT_TRUE(GetOrCreateCategoryByName("__test_ab,__test_a", &cat_3)); |
| 92 ASSERT_FALSE(cat_3->is_enabled()); |
| 93 ASSERT_EQ(0u, cat_3->enabled_filters()); |
| 94 |
| 95 int num_test_categories_seen = 0; |
| 96 for (const TraceCategory& cat : GetAllCategories()) { |
| 97 if (strcmp(cat.name(), kMetadataName) == 0) |
| 98 ASSERT_TRUE(CategoryRegistry::IsBuiltinCategory(&cat)); |
| 99 |
| 100 if (strncmp(cat.name(), "__test", 6) == 0) { |
| 101 ASSERT_FALSE(CategoryRegistry::IsBuiltinCategory(&cat)); |
| 102 num_test_categories_seen++; |
| 103 } |
| 104 } |
| 105 ASSERT_EQ(3, num_test_categories_seen); |
| 106 ASSERT_TRUE(g_initializer_check); |
| 107 } |
| 108 |
| 109 // Tries to cover the case of multiple threads creating the same category |
| 110 // simultaeously. Should never end up with distinct entries with the same name. |
| 111 TEST_F(TraceCategoryTest, ThreadRaces) { |
| 112 const int kNumThreads = 32; |
| 113 std::unique_ptr<Thread> threads[kNumThreads]; |
| 114 for (int i = 0; i < kNumThreads; i++) { |
| 115 threads[i].reset(new Thread("test thread")); |
| 116 threads[i]->Start(); |
| 117 } |
| 118 WaitableEvent sync_event(WaitableEvent::ResetPolicy::MANUAL, |
| 119 WaitableEvent::InitialState::NOT_SIGNALED); |
| 120 for (int i = 0; i < kNumThreads; i++) { |
| 121 threads[i]->task_runner()->PostTask( |
| 122 FROM_HERE, Bind(&TestRaceThreadMain, Unretained(&sync_event))); |
| 123 } |
| 124 sync_event.Signal(); |
| 125 for (int i = 0; i < kNumThreads; i++) |
| 126 threads[i]->Stop(); |
| 127 |
| 128 int num_times_seen = 0; |
| 129 for (const TraceCategory& cat : GetAllCategories()) { |
| 130 if (strcmp(cat.name(), "__test_race") == 0) |
| 131 num_times_seen++; |
| 132 } |
| 133 ASSERT_EQ(1, num_times_seen); |
| 134 } |
| 135 |
| 136 } // namespace trace_event |
| 137 } // namespace base |
OLD | NEW |