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