1 // Copyright 2013 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 "chrome/browser/sync/test/integration/status_change_checker.h" 6 7 #include <sstream> 8 #include <string> 9 10 #include "base/bind.h" 11 #include "base/command_line.h" 12 #include "base/logging.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "base/timer/timer.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 namespace { 18 19 constexpr base::TimeDelta kDefaultTimeout = base::TimeDelta::FromSeconds(30); 20 GetTimeoutFromCommandLineOrDefault()21base::TimeDelta GetTimeoutFromCommandLineOrDefault() { 22 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( 23 "sync-status-change-checker-timeout")) { 24 return kDefaultTimeout; 25 } 26 std::string timeout_string( 27 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 28 "sync-status-change-checker-timeout")); 29 int timeout_in_seconds = 0; 30 if (!base::StringToInt(timeout_string, &timeout_in_seconds)) { 31 LOG(FATAL) << "Timeout value \"" << timeout_string << "\" was parsed as " 32 << timeout_in_seconds; 33 } 34 return base::TimeDelta::FromSeconds(timeout_in_seconds); 35 } 36 37 } // namespace 38 StatusChangeChecker()39StatusChangeChecker::StatusChangeChecker() 40 : timeout_(GetTimeoutFromCommandLineOrDefault()), 41 run_loop_(base::RunLoop::Type::kNestableTasksAllowed) {} 42 43 StatusChangeChecker::~StatusChangeChecker() = default; 44 Wait()45bool StatusChangeChecker::Wait() { 46 std::ostringstream s; 47 if (IsExitConditionSatisfied(&s)) { 48 DVLOG(1) << "Already satisfied: " << s.str(); 49 wait_done_called_ = true; 50 WaitDone(); 51 } else { 52 DVLOG(1) << "Blocking: " << s.str(); 53 StartBlockingWait(); 54 } 55 return !TimedOut(); 56 } 57 TimedOut() const58bool StatusChangeChecker::TimedOut() const { 59 return timed_out_; 60 } 61 StopWaiting()62void StatusChangeChecker::StopWaiting() { 63 if (run_loop_.running()) { 64 // Note that we can get here multiple times in some situations, because 65 // RunLoop::Quit() doesn't guarantee that it actually quits immediately. 66 // Make sure that WaitDone() still gets called only once. 67 if (!wait_done_called_) { 68 wait_done_called_ = true; 69 WaitDone(); 70 } 71 run_loop_.Quit(); 72 } 73 } 74 CheckExitCondition()75void StatusChangeChecker::CheckExitCondition() { 76 if (!run_loop_.running()) { 77 return; 78 } 79 80 std::ostringstream s; 81 if (IsExitConditionSatisfied(&s)) { 82 DVLOG(1) << "Await -> Condition met: " << s.str(); 83 StopWaiting(); 84 } else { 85 DVLOG(1) << "Await -> Condition not met: " << s.str(); 86 } 87 } 88 StartBlockingWait()89void StatusChangeChecker::StartBlockingWait() { 90 DCHECK(!run_loop_.running()); 91 92 base::OneShotTimer timer; 93 timer.Start( 94 FROM_HERE, timeout_, 95 base::BindOnce(&StatusChangeChecker::OnTimeout, base::Unretained(this))); 96 97 run_loop_.Run(); 98 } 99 OnTimeout()100void StatusChangeChecker::OnTimeout() { 101 timed_out_ = true; 102 103 std::ostringstream s; 104 if (IsExitConditionSatisfied(&s)) { 105 ADD_FAILURE() << "Await -> Timed out despite conditions being satisfied."; 106 } else { 107 ADD_FAILURE() << "Await -> Timed out: " << s.str(); 108 } 109 110 StopWaiting(); 111 } 112