| // Copyright 2018 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 "base/task_scheduler/service_thread.h" | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/debug/stack_trace.h" | 
 | #include "base/task_scheduler/task_scheduler.h" | 
 | #include "base/task_scheduler/task_scheduler_impl.h" | 
 | #include "base/test/histogram_tester.h" | 
 | #include "base/threading/platform_thread.h" | 
 | #include "base/time/time.h" | 
 | #include "build/build_config.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace base { | 
 | namespace internal { | 
 |  | 
 | namespace { | 
 |  | 
 | // Verifies that |query| is found on the current stack. Ignores failures if this | 
 | // configuration doesn't have symbols. | 
 | void VerifyHasStringOnStack(const std::string& query) { | 
 |   const std::string stack = debug::StackTrace().ToString(); | 
 |   SCOPED_TRACE(stack); | 
 |   const bool found_on_stack = stack.find(query) != std::string::npos; | 
 |   const bool stack_has_symbols = | 
 |       stack.find("SchedulerWorker") != std::string::npos; | 
 |   EXPECT_TRUE(found_on_stack || !stack_has_symbols) << query; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | #if defined(OS_POSIX) | 
 | // Many POSIX bots flakily crash on |debug::StackTrace().ToString()|, | 
 | // https://crbug.com/840429. | 
 | #define MAYBE_StackHasIdentifyingFrame DISABLED_StackHasIdentifyingFrame | 
 | #else | 
 | #define MAYBE_StackHasIdentifyingFrame StackHasIdentifyingFrame | 
 | #endif | 
 |  | 
 | TEST(TaskSchedulerServiceThreadTest, MAYBE_StackHasIdentifyingFrame) { | 
 |   ServiceThread service_thread(nullptr); | 
 |   service_thread.Start(); | 
 |  | 
 |   service_thread.task_runner()->PostTask( | 
 |       FROM_HERE, BindOnce(&VerifyHasStringOnStack, "ServiceThread")); | 
 |  | 
 |   service_thread.FlushForTesting(); | 
 | } | 
 |  | 
 | // Integration test verifying that a service thread running in a fully | 
 | // integrated TaskScheduler environment results in reporting | 
 | // HeartbeatLatencyMicroseconds metrics. | 
 | TEST(TaskSchedulerServiceThreadIntegrationTest, HeartbeatLatencyReport) { | 
 |   TaskScheduler::SetInstance( | 
 |       std::make_unique<internal::TaskSchedulerImpl>("Test")); | 
 |   TaskScheduler::GetInstance()->StartWithDefaultParams(); | 
 |  | 
 |   static constexpr const char* kExpectedMetrics[] = { | 
 |       "TaskScheduler.HeartbeatLatencyMicroseconds.Test." | 
 |       "UserBlockingTaskPriority", | 
 |       "TaskScheduler.HeartbeatLatencyMicroseconds.Test." | 
 |       "UserBlockingTaskPriority_MayBlock", | 
 |       "TaskScheduler.HeartbeatLatencyMicroseconds.Test." | 
 |       "UserVisibleTaskPriority", | 
 |       "TaskScheduler.HeartbeatLatencyMicroseconds.Test." | 
 |       "UserVisibleTaskPriority_MayBlock", | 
 |       "TaskScheduler.HeartbeatLatencyMicroseconds.Test." | 
 |       "BackgroundTaskPriority", | 
 |       "TaskScheduler.HeartbeatLatencyMicroseconds.Test." | 
 |       "BackgroundTaskPriority_MayBlock"}; | 
 |  | 
 |   constexpr TimeDelta kReasonableTimeout = TimeDelta::FromSeconds(6); | 
 |   constexpr TimeDelta kBusyWaitTime = TimeDelta::FromMilliseconds(100); | 
 |  | 
 |   const TimeTicks start_time = TimeTicks::Now(); | 
 |  | 
 |   HistogramTester tester; | 
 |   for (const char* expected_metric : kExpectedMetrics) { | 
 |     for (int i = 0; tester.GetAllSamples(expected_metric).empty(); ++i) { | 
 |       if (TimeTicks::Now() - start_time > kReasonableTimeout) | 
 |         LOG(WARNING) << "Waiting a while for " << expected_metric; | 
 |       PlatformThread::Sleep(kBusyWaitTime); | 
 |     } | 
 |   } | 
 |  | 
 |   TaskScheduler::GetInstance()->JoinForTesting(); | 
 |   TaskScheduler::SetInstance(nullptr); | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace base |