Commit 40841e39 authored by Bailey Berro's avatar Bailey Berro Committed by Commit Bot

Add SystemRoutineController Power Routines

This change adds the Battery Charge and Battery Discharge Routines to
the SystemRoutineController interface.

Example of routines being called from frontend:
https://source.chromium.org/chromium/chromium/src/+/master:chromeos/components/diagnostics_ui/resources/routine_list_executor.js;l=88-118

Bug: 1128204
Change-Id: I1b4589a69b66bd7a62899d40a297ef96b4e8f877
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2488747
Commit-Queue: Bailey Berro <baileyberro@chromium.org>
Auto-Submit: Bailey Berro <baileyberro@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarZentaro Kavanagh <zentaro@chromium.org>
Cr-Commit-Position: refs/heads/master@{#828460}
parent 1f55f7c6
......@@ -3,6 +3,7 @@ include_rules = [
"+chromeos/grit/chromeos_diagnostics_app_resources.h",
"+chromeos/strings/grit/chromeos_strings.h",
"+content/public/browser",
"+services/data_decoder/public",
"+ui/base",
"+ui/resources",
"+ui/webui",
......
......@@ -27,6 +27,7 @@ static_library("backend") {
"//chromeos/dbus/power:power_manager_proto",
"//chromeos/services/cros_healthd/public/cpp",
"//chromeos/services/cros_healthd/public/mojom",
"//services/data_decoder/public/cpp",
]
}
......@@ -49,6 +50,7 @@ source_set("unit_tests") {
"//chromeos/dbus/power:power_manager_proto",
"//chromeos/services/cros_healthd/public/cpp",
"//chromeos/services/cros_healthd/public/mojom",
"//services/data_decoder/public/cpp:test_support",
"//testing/gtest",
]
}
......@@ -5,9 +5,15 @@
#include "chromeos/components/diagnostics_ui/backend/system_routine_controller.h"
#include "base/bind.h"
#include "base/containers/span.h"
#include "base/files/file.h"
#include "base/logging.h"
#include "base/optional.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "chromeos/components/diagnostics_ui/backend/cros_healthd_helpers.h"
#include "chromeos/services/cros_healthd/public/cpp/service_connection.h"
......@@ -17,6 +23,9 @@ namespace {
namespace healthd = cros_healthd::mojom;
constexpr uint32_t kBatteryChargeMinimumPercent = 0;
constexpr uint32_t kBatteryDischargeMaximumPercent = 100;
constexpr uint32_t kBatteryDurationInSeconds = 30;
constexpr uint32_t kCpuCacheDurationInSeconds = 60;
constexpr uint32_t kCpuFloatingPointDurationInSeconds = 60;
constexpr uint32_t kCpuPrimeDurationInSeconds = 60;
......@@ -24,6 +33,9 @@ constexpr uint32_t kCpuStressDurationInSeconds = 60;
constexpr uint32_t kExpectedMemoryDurationInSeconds = 1000;
constexpr uint32_t kRoutineResultRefreshIntervalInSeconds = 1;
constexpr char kChargePercentKey[] = "chargePercent";
constexpr char kResultDetailsKey[] = "resultDetails";
mojom::RoutineResultInfoPtr ConstructStandardRoutineResultInfoPtr(
mojom::RoutineType type,
mojom::StandardRoutineResult result) {
......@@ -58,8 +70,24 @@ mojom::StandardRoutineResult TestStatusToResult(
}
}
mojom::RoutineResultInfoPtr ConstructPowerRoutineResultInfoPtr(
mojom::RoutineType type,
mojom::StandardRoutineResult result,
double percent_change,
uint32_t seconds_elapsed) {
auto power_result =
mojom::PowerRoutineResult::New(result, percent_change, seconds_elapsed);
auto routine_result =
mojom::RoutineResult::NewPowerResult(std::move(power_result));
return mojom::RoutineResultInfo::New(type, std::move(routine_result));
}
uint32_t GetExpectedRoutineDurationInSeconds(mojom::RoutineType routine_type) {
switch (routine_type) {
case mojom::RoutineType::kBatteryCharge:
return kBatteryDurationInSeconds;
case mojom::RoutineType::kBatteryDischarge:
return kBatteryDurationInSeconds;
case mojom::RoutineType::kCpuCache:
return kCpuCacheDurationInSeconds;
case mojom::RoutineType::kCpuFloatingPoint:
......@@ -73,6 +101,21 @@ uint32_t GetExpectedRoutineDurationInSeconds(mojom::RoutineType routine_type) {
}
}
bool IsPowerRoutine(mojom::RoutineType routine_type) {
return routine_type == mojom::RoutineType::kBatteryCharge ||
routine_type == mojom::RoutineType::kBatteryDischarge;
}
std::string ReadMojoHandleToJsonString(mojo::PlatformHandle handle) {
base::File file(handle.ReleaseFD());
std::vector<uint8_t> contents;
contents.resize(file.GetLength());
if (!file.ReadAndCheck(0, contents)) {
return std::string();
}
return std::string(contents.begin(), contents.end());
}
} // namespace
SystemRoutineController::SystemRoutineController() {
......@@ -108,6 +151,20 @@ void SystemRoutineController::ExecuteRoutine(mojom::RoutineType routine_type) {
BindCrosHealthdDiagnosticsServiceIfNeccessary();
switch (routine_type) {
case mojom::RoutineType::kBatteryCharge:
diagnostics_service_->RunBatteryDischargeRoutine(
kBatteryDurationInSeconds, kBatteryChargeMinimumPercent,
base::BindOnce(&SystemRoutineController::OnPowerRoutineStarted,
base::Unretained(this), routine_type));
return;
case mojom::RoutineType::kBatteryDischarge:
diagnostics_service_->RunBatteryDischargeRoutine(
kBatteryDurationInSeconds, kBatteryDischargeMaximumPercent,
base::BindOnce(&SystemRoutineController::OnPowerRoutineStarted,
base::Unretained(this), routine_type));
return;
case mojom::RoutineType::kCpuCache:
diagnostics_service_->RunCpuCacheRoutine(
healthd::NullableUint32::New(kCpuCacheDurationInSeconds),
......@@ -143,6 +200,7 @@ void SystemRoutineController::ExecuteRoutine(mojom::RoutineType routine_type) {
void SystemRoutineController::OnRoutineStarted(
mojom::RoutineType routine_type,
healthd::RunRoutineResponsePtr response_ptr) {
DCHECK(!IsPowerRoutine(routine_type));
// Check for error conditions.
// TODO(baileyberro): Handle additional statuses.
if (response_ptr->status ==
......@@ -163,13 +221,64 @@ void SystemRoutineController::OnRoutineStarted(
routine_type, id);
}
void SystemRoutineController::OnPowerRoutineStarted(
mojom::RoutineType routine_type,
healthd::RunRoutineResponsePtr response_ptr) {
DCHECK(IsPowerRoutine(routine_type));
// TODO(baileyberro): Handle additional statuses.
if (response_ptr->status != healthd::DiagnosticRoutineStatusEnum::kWaiting) {
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
return;
}
ContinuePowerRoutine(routine_type, response_ptr->id);
}
void SystemRoutineController::ContinuePowerRoutine(
mojom::RoutineType routine_type,
int32_t id) {
DCHECK(IsPowerRoutine(routine_type));
BindCrosHealthdDiagnosticsServiceIfNeccessary();
diagnostics_service_->GetRoutineUpdate(
id, healthd::DiagnosticRoutineCommandEnum::kContinue,
/*should_include_output=*/true,
base::BindOnce(&SystemRoutineController::OnPowerRoutineContinued,
base::Unretained(this), routine_type, id));
}
void SystemRoutineController::OnPowerRoutineContinued(
mojom::RoutineType routine_type,
int32_t id,
healthd::RoutineUpdatePtr update_ptr) {
DCHECK(IsPowerRoutine(routine_type));
const healthd::NonInteractiveRoutineUpdate* update =
GetNonInteractiveRoutineUpdate(*update_ptr);
if (!update ||
update->status != healthd::DiagnosticRoutineStatusEnum::kRunning) {
DVLOG(2) << "Failed to resume power routine.";
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
return;
}
ScheduleCheckRoutineStatus(GetExpectedRoutineDurationInSeconds(routine_type),
routine_type, id);
}
void SystemRoutineController::CheckRoutineStatus(
mojom::RoutineType routine_type,
int32_t id) {
BindCrosHealthdDiagnosticsServiceIfNeccessary();
const bool should_include_output = IsPowerRoutine(routine_type);
diagnostics_service_->GetRoutineUpdate(
id, healthd::DiagnosticRoutineCommandEnum::kGetStatus,
/*include_output=*/false,
should_include_output,
base::BindOnce(&SystemRoutineController::OnRoutineStatusUpdated,
base::Unretained(this), routine_type, id));
}
......@@ -178,6 +287,11 @@ void SystemRoutineController::OnRoutineStatusUpdated(
mojom::RoutineType routine_type,
int32_t id,
healthd::RoutineUpdatePtr update_ptr) {
if (IsPowerRoutine(routine_type)) {
HandlePowerRoutineStatusUpdate(routine_type, id, std::move(update_ptr));
return;
}
const healthd::NonInteractiveRoutineUpdate* update =
GetNonInteractiveRoutineUpdate(*update_ptr);
......@@ -190,6 +304,52 @@ void SystemRoutineController::OnRoutineStatusUpdated(
const healthd::DiagnosticRoutineStatusEnum status = update->status;
switch (status) {
case healthd::DiagnosticRoutineStatusEnum::kRunning:
// If still running, continue to repoll until it is finished.
// TODO(baileyberro): Consider adding a timeout mechanism.
ScheduleCheckRoutineStatus(kRoutineResultRefreshIntervalInSeconds,
routine_type, id);
return;
case healthd::DiagnosticRoutineStatusEnum::kPassed:
case healthd::DiagnosticRoutineStatusEnum::kFailed:
OnStandardRoutineResult(routine_type, TestStatusToResult(status));
return;
case healthd::DiagnosticRoutineStatusEnum::kCancelled:
case healthd::DiagnosticRoutineStatusEnum::kError:
case healthd::DiagnosticRoutineStatusEnum::kFailedToStart:
case healthd::DiagnosticRoutineStatusEnum::kUnsupported:
case healthd::DiagnosticRoutineStatusEnum::kReady:
case healthd::DiagnosticRoutineStatusEnum::kWaiting:
case healthd::DiagnosticRoutineStatusEnum::kRemoved:
case healthd::DiagnosticRoutineStatusEnum::kCancelling:
case healthd::DiagnosticRoutineStatusEnum::kNotRun:
// Any other reason, report failure.
DVLOG(2) << "Routine failed: " << update->status_message;
OnStandardRoutineResult(routine_type, TestStatusToResult(status));
return;
}
}
void SystemRoutineController::HandlePowerRoutineStatusUpdate(
mojom::RoutineType routine_type,
int32_t id,
cros_healthd::mojom::RoutineUpdatePtr update_ptr) {
DCHECK(IsPowerRoutine(routine_type));
const healthd::NonInteractiveRoutineUpdate* update =
GetNonInteractiveRoutineUpdate(*update_ptr);
if (!update) {
DVLOG(2) << "Invalid routine update";
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
return;
}
const healthd::DiagnosticRoutineStatusEnum status = update->status;
// If still running, continue to repoll until it is finished.
// TODO(baileyberro): Consider adding a timeout mechanism.
if (status == healthd::DiagnosticRoutineStatusEnum::kRunning) {
......@@ -200,19 +360,25 @@ void SystemRoutineController::OnRoutineStatusUpdated(
// If test passed, report result.
if (status == healthd::DiagnosticRoutineStatusEnum::kPassed) {
OnStandardRoutineResult(routine_type, TestStatusToResult(status));
ParsePowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kTestPassed,
std::move(update_ptr->output));
return;
}
// If test failed, report result.
if (status == healthd::DiagnosticRoutineStatusEnum::kFailed) {
OnStandardRoutineResult(routine_type, TestStatusToResult(status));
ParsePowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kTestFailed,
std::move(update_ptr->output));
return;
}
// Any other reason, report failure.
DVLOG(2) << "Routine failed: " << update->status_message;
OnStandardRoutineResult(routine_type, TestStatusToResult(status));
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
}
bool SystemRoutineController::IsRoutineRunning() const {
......@@ -229,6 +395,96 @@ void SystemRoutineController::ScheduleCheckRoutineStatus(
base::Unretained(this), routine_type, id));
}
void SystemRoutineController::ParsePowerRoutineResult(
mojom::RoutineType routine_type,
mojom::StandardRoutineResult result,
mojo::ScopedHandle output_handle) {
if (!output_handle.is_valid()) {
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
return;
}
mojo::PlatformHandle platform_handle =
mojo::UnwrapPlatformHandle(std::move(output_handle));
if (!platform_handle.is_valid()) {
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
return;
}
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&ReadMojoHandleToJsonString, std::move(platform_handle)),
base::BindOnce(&SystemRoutineController::OnPowerRoutineResultFetched,
weak_factory_.GetWeakPtr(), routine_type));
}
void SystemRoutineController::OnPowerRoutineResultFetched(
mojom::RoutineType routine_type,
const std::string& file_contents) {
if (file_contents.empty()) {
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
DVLOG(2) << "Empty Power Routine Result File.";
return;
}
data_decoder::DataDecoder::ParseJsonIsolated(
file_contents,
base::BindOnce(&SystemRoutineController::OnPowerRoutineJsonParsed,
weak_factory_.GetWeakPtr(), routine_type));
return;
}
void SystemRoutineController::OnPowerRoutineJsonParsed(
mojom::RoutineType routine_type,
data_decoder::DataDecoder::ValueOrError result) {
if (!result.value) {
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
DVLOG(2) << "JSON parsing failed: " << *result.error;
return;
}
const base::Value& parsed_json = *result.value;
if (parsed_json.type() != base::Value::Type::DICTIONARY) {
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
DVLOG(2) << "Malformed Routine Result File.";
return;
}
const base::Value* result_details_dict =
parsed_json.FindDictKey(kResultDetailsKey);
if (!result_details_dict) {
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
DVLOG(2) << "Malformed Routine Result File.";
return;
}
base::Optional<double> charge_percent_opt =
result_details_dict->FindDoubleKey(kChargePercentKey);
if (!charge_percent_opt.has_value()) {
OnPowerRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError,
/*percent_change=*/0, /*seconds_elapsed=*/0);
DVLOG(2) << "Malformed Routine Result File.";
return;
}
OnPowerRoutineResult(routine_type, mojom::StandardRoutineResult::kTestPassed,
*charge_percent_opt, kBatteryDurationInSeconds);
}
void SystemRoutineController::OnStandardRoutineResult(
mojom::RoutineType routine_type,
mojom::StandardRoutineResult result) {
......@@ -239,6 +495,18 @@ void SystemRoutineController::OnStandardRoutineResult(
inflight_routine_runner_.reset();
}
void SystemRoutineController::OnPowerRoutineResult(
mojom::RoutineType routine_type,
mojom::StandardRoutineResult result,
double percent_change,
uint32_t seconds_elapsed) {
DCHECK(IsRoutineRunning());
auto result_info = ConstructPowerRoutineResultInfoPtr(
routine_type, result, percent_change, seconds_elapsed);
inflight_routine_runner_->OnRoutineResult(std::move(result_info));
inflight_routine_runner_.reset();
}
void SystemRoutineController::BindCrosHealthdDiagnosticsServiceIfNeccessary() {
if (!diagnostics_service_ || !diagnostics_service_.is_connected()) {
cros_healthd::ServiceConnection::GetInstance()->GetDiagnosticsService(
......
......@@ -7,11 +7,13 @@
#include <memory>
#include "base/memory/weak_ptr.h"
#include "chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
namespace base {
class OneShotTimer;
......@@ -52,21 +54,52 @@ class SystemRoutineController : public mojom::SystemRoutineController {
mojom::RoutineType routine_type,
cros_healthd::mojom::RunRoutineResponsePtr response_ptr);
void OnPowerRoutineStarted(
mojom::RoutineType routine_type,
cros_healthd::mojom::RunRoutineResponsePtr response_ptr);
void ContinuePowerRoutine(mojom::RoutineType routine_type, int32_t id);
void OnPowerRoutineContinued(
mojom::RoutineType routine_type,
int32_t id,
cros_healthd::mojom::RoutineUpdatePtr update_ptr);
void CheckRoutineStatus(mojom::RoutineType routine_type, int32_t id);
void OnRoutineStatusUpdated(mojom::RoutineType routine_type,
int32_t id,
cros_healthd::mojom::RoutineUpdatePtr update_ptr);
void HandlePowerRoutineStatusUpdate(
mojom ::RoutineType routine_type,
int32_t id,
cros_healthd::mojom::RoutineUpdatePtr update_ptr);
bool IsRoutineRunning() const;
void ScheduleCheckRoutineStatus(uint32_t duration_in_seconds,
mojom::RoutineType routine_type,
int32_t id);
void ParsePowerRoutineResult(mojom::RoutineType routine_type,
mojom::StandardRoutineResult result,
mojo::ScopedHandle output_handle);
void OnPowerRoutineResultFetched(mojom::RoutineType routine_type,
const std::string& file_contents);
void OnPowerRoutineJsonParsed(mojom::RoutineType routine_type,
data_decoder::DataDecoder::ValueOrError result);
void OnStandardRoutineResult(mojom::RoutineType routine_type,
mojom::StandardRoutineResult result);
void OnPowerRoutineResult(mojom::RoutineType routine_type,
mojom::StandardRoutineResult result,
double percent_change,
uint32_t seconds_elapsed);
void BindCrosHealthdDiagnosticsServiceIfNeccessary();
void OnDiagnosticsServiceDisconnected();
......@@ -80,6 +113,8 @@ class SystemRoutineController : public mojom::SystemRoutineController {
diagnostics_service_;
mojo::Receiver<mojom::SystemRoutineController> receiver_{this};
base::WeakPtrFactory<SystemRoutineController> weak_factory_{this};
};
} // namespace diagnostics
......
......@@ -4,12 +4,18 @@
#include "chromeos/components/diagnostics_ui/backend/system_routine_controller.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_writer.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "chromeos/dbus/cros_healthd/fake_cros_healthd_client.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
......@@ -18,6 +24,9 @@ namespace {
namespace healthd = cros_healthd::mojom;
constexpr char kChargePercentKey[] = "chargePercent";
constexpr char kResultDetailsKey[] = "resultDetails";
void SetCrosHealthdRunRoutineResponse(
healthd::RunRoutineResponsePtr& response) {
cros_healthd::FakeCrosHealthdClient::Get()->SetRunRoutineResponseForTesting(
......@@ -37,7 +46,8 @@ void SetCrosHealthdRoutineUpdateResponse(healthd::RoutineUpdatePtr& response) {
void SetNonInteractiveRoutineUpdateResponse(
uint32_t percent_complete,
healthd::DiagnosticRoutineStatusEnum status) {
healthd::DiagnosticRoutineStatusEnum status,
mojo::ScopedHandle output_handle) {
DCHECK_GE(percent_complete, 0u);
DCHECK_LE(percent_complete, 100u);
......@@ -48,6 +58,7 @@ void SetNonInteractiveRoutineUpdateResponse(
std::move(non_interactive_update));
auto routine_update = healthd::RoutineUpdate::New();
routine_update->progress_percent = percent_complete;
routine_update->output = std::move(output_handle);
routine_update->routine_update_union = std::move(routine_update_union);
SetCrosHealthdRoutineUpdateResponse(routine_update);
......@@ -63,6 +74,40 @@ void VerifyRoutineResult(const mojom::RoutineResultInfo& result_info,
EXPECT_EQ(expected_routine_type, result_info.type);
}
void VerifyRoutineResult(const mojom::RoutineResultInfo& result_info,
mojom::RoutineType expected_routine_type,
mojom::PowerRoutineResultPtr expected_result) {
const mojom::PowerRoutineResultPtr& actual_result =
result_info.result->get_power_result();
EXPECT_EQ(expected_result->simple_result, actual_result->simple_result);
EXPECT_EQ(expected_result->percent_change, actual_result->percent_change);
EXPECT_EQ(expected_result->time_elapsed_seconds,
actual_result->time_elapsed_seconds);
EXPECT_EQ(expected_routine_type, result_info.type);
}
mojom::PowerRoutineResultPtr ConstructPowerRoutineResult(
mojom::StandardRoutineResult simple_result,
double percent_change,
uint32_t time_elapsed_seconds) {
return mojom::PowerRoutineResult::New(simple_result, percent_change,
time_elapsed_seconds);
}
std::string ConstructPowerRoutineResultJson(double charge_percent) {
base::Value result_dict(base::Value::Type::DICTIONARY);
result_dict.SetKey(kChargePercentKey, base::Value(charge_percent));
base::Value output_dict(base::Value::Type::DICTIONARY);
output_dict.SetKey(kResultDetailsKey, std::move(result_dict));
std::string json;
const bool serialize_success = base::JSONWriter::Write(output_dict, &json);
DCHECK(serialize_success);
return json;
}
} // namespace
struct FakeRoutineRunner : public mojom::RoutineRunner {
......@@ -92,9 +137,31 @@ class SystemRoutineControllerTest : public testing::Test {
}
protected:
mojo::ScopedHandle CreateMojoHandleForPowerRoutine(double charge_percent) {
return CreateMojoHandle(ConstructPowerRoutineResultJson(charge_percent));
}
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
std::unique_ptr<SystemRoutineController> system_routine_controller_;
private:
mojo::ScopedHandle CreateMojoHandle(const std::string& contents) {
const bool temp_success = temp_dir_.CreateUniqueTempDir();
DCHECK(temp_success);
base::FilePath path;
base::ScopedFD fd =
base::CreateAndOpenFdForTemporaryFileInDir(temp_dir_.GetPath(), &path);
DCHECK(fd.is_valid());
const bool write_success =
base::WriteFileDescriptor(fd.get(), contents.data(), contents.size());
DCHECK(write_success);
return mojo::WrapPlatformFile(std::move(fd));
}
base::ScopedTempDir temp_dir_;
data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
};
TEST_F(SystemRoutineControllerTest, RejectedByCrosHealthd) {
......@@ -153,7 +220,8 @@ TEST_F(SystemRoutineControllerTest, CpuStressSuccess) {
// Update the status on cros_healthd.
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed,
mojo::ScopedHandle());
// Before the update interval, the routine status is not processed.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(59));
......@@ -181,7 +249,8 @@ TEST_F(SystemRoutineControllerTest, CpuStressFailure) {
// Update the status on cros_healthd.
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kFailed);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kFailed,
mojo::ScopedHandle());
// Before the update interval, the routine status is not processed.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(59));
......@@ -209,7 +278,8 @@ TEST_F(SystemRoutineControllerTest, CpuStressStillRunning) {
// Update the status on cros_healthd to signify the routine is still running.
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kRunning);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kRunning,
mojo::ScopedHandle());
// Before the update interval, the routine status is not processed.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(59));
......@@ -222,7 +292,8 @@ TEST_F(SystemRoutineControllerTest, CpuStressStillRunning) {
// Update the status on cros_healthd to signify the routine is completed
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed,
mojo::ScopedHandle());
// Fast forward by the refresh interval.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
......@@ -246,7 +317,8 @@ TEST_F(SystemRoutineControllerTest, CpuStressStillRunningMultipleIntervals) {
// Update the status on cros_healthd to signify the routine is still running.
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kRunning);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kRunning,
mojo::ScopedHandle());
// Before the update interval, the routine status is not processed.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(59));
......@@ -258,7 +330,8 @@ TEST_F(SystemRoutineControllerTest, CpuStressStillRunningMultipleIntervals) {
EXPECT_TRUE(routine_runner.result.is_null());
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kRunning);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kRunning,
mojo::ScopedHandle());
// After another refresh interval, the routine is still running.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
......@@ -266,7 +339,8 @@ TEST_F(SystemRoutineControllerTest, CpuStressStillRunningMultipleIntervals) {
// Update the status on cros_healthd to signify the routine is completed
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed,
mojo::ScopedHandle());
// After a second refresh interval, the routine is completed.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
......@@ -290,7 +364,8 @@ TEST_F(SystemRoutineControllerTest, TwoConsecutiveRoutines) {
// Update the status on cros_healthd.
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed,
mojo::ScopedHandle());
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(60));
EXPECT_FALSE(routine_runner_1.result.is_null());
VerifyRoutineResult(*routine_runner_1.result, mojom::RoutineType::kCpuStress,
......@@ -311,12 +386,45 @@ TEST_F(SystemRoutineControllerTest, TwoConsecutiveRoutines) {
// Update the status on cros_healthd.
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kFailed);
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kFailed,
mojo::ScopedHandle());
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(60));
EXPECT_FALSE(routine_runner_2.result.is_null());
VerifyRoutineResult(*routine_runner_2.result, mojom::RoutineType::kCpuStress,
mojom::StandardRoutineResult::kTestFailed);
}
TEST_F(SystemRoutineControllerTest, PowerRoutineSuccess) {
SetRunRoutineResponse(/*id=*/1,
healthd::DiagnosticRoutineStatusEnum::kWaiting);
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/10, healthd::DiagnosticRoutineStatusEnum::kRunning,
mojo::ScopedHandle());
FakeRoutineRunner routine_runner;
system_routine_controller_->RunRoutine(
mojom::RoutineType::kBatteryCharge,
routine_runner.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
// Assert that the routine is not complete.
EXPECT_TRUE(routine_runner.result.is_null());
const uint8_t expected_percent_charge = 2;
const uint32_t expected_time_elapsed_seconds = 30;
SetNonInteractiveRoutineUpdateResponse(
/*percent_complete=*/100, healthd::DiagnosticRoutineStatusEnum::kPassed,
CreateMojoHandleForPowerRoutine(expected_percent_charge));
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(31));
EXPECT_FALSE(routine_runner.result.is_null());
VerifyRoutineResult(
*routine_runner.result, mojom::RoutineType::kBatteryCharge,
ConstructPowerRoutineResult(mojom::StandardRoutineResult::kTestPassed,
expected_percent_charge,
expected_time_elapsed_seconds));
}
} // namespace diagnostics
} // namespace chromeos
......@@ -5,6 +5,8 @@
module chromeos.diagnostics.mojom;
enum RoutineType {
kBatteryCharge,
kBatteryDischarge,
kCpuCache,
kCpuStress,
kCpuFloatingPoint,
......@@ -19,8 +21,15 @@ enum StandardRoutineResult {
kUnableToRun,
};
struct PowerRoutineResult {
StandardRoutineResult simple_result;
double percent_change;
uint32 time_elapsed_seconds;
};
union RoutineResult {
StandardRoutineResult simple_result;
PowerRoutineResult power_result;
};
struct RoutineResultInfo {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment