0

cros_healthd: add prime search routines

Add a routine to calculate prime number repeatedly and validate the
calculation results are correct in a duration.

Bug: b:146513388
Test: chromeos_unittests --gtest_filter=CrosHealthdServiceConnectionTest.*
Change-Id: I29c3d71d2b0f9d86043e552e135bc9178c95014f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2049986
Commit-Queue: Oleh Lamzin <lamzin@google.com>
Reviewed-by: Oleh Lamzin <lamzin@google.com>
Reviewed-by: Maksim Ivanov <emaxx@chromium.org>
Reviewed-by: Paul Moy <pmoy@chromium.org>
Reviewed-by: Steven Bennetts <stevenjb@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#754004}
This commit is contained in:
Eric Kuo
2020-03-27 14:18:05 +00:00
committed by Commit Bot
parent 54902a807c
commit 8cb958bcb4
9 changed files with 243 additions and 0 deletions

@ -400,6 +400,31 @@ void DeviceCommandRunRoutineJob::RunImpl(CallbackWithResult succeeded_callback,
std::move(failed_callback)));
break;
}
case chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kPrimeSearch: {
constexpr char kLengthSecondsFieldName[] = "lengthSeconds";
constexpr char kMaxNumFieldName[] = "maxNum";
base::Optional<int> length_seconds =
params_dict_.FindIntKey(kLengthSecondsFieldName);
base::Optional<int> max_num = params_dict_.FindIntKey(kMaxNumFieldName);
if (!length_seconds.has_value() || length_seconds.value() < 0 ||
!max_num.has_value() || max_num.value() < 0) {
SYSLOG(ERROR) << "Invalid parameters for prime search routine.";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(failed_callback),
std::make_unique<Payload>(
MakeInvalidParametersResponse())));
break;
}
auto exec_duration = base::TimeDelta::FromSeconds(length_seconds.value());
chromeos::cros_healthd::ServiceConnection::GetInstance()
->RunPrimeSearchRoutine(
exec_duration, max_num.value(),
base::BindOnce(
&DeviceCommandRunRoutineJob::OnCrosHealthdResponseReceived,
weak_ptr_factory_.GetWeakPtr(), std::move(succeeded_callback),
std::move(failed_callback)));
break;
}
}
}

@ -67,6 +67,10 @@ constexpr char kNvmeSelfTestTypeFieldName[] = "nvmeSelfTestType";
constexpr char kTypeFieldName[] = "type";
constexpr char kFileSizeMbFieldName[] = "fileSizeMb";
// String constants identifying the parameter fields for the prime search
// routine
constexpr char kMaxNumFieldName[] = "maxNum";
// Dummy values to populate cros_healthd's RunRoutineResponse.
constexpr uint32_t kId = 11;
constexpr chromeos::cros_healthd::mojom::DiagnosticRoutineStatusEnum kStatus =
@ -1400,4 +1404,149 @@ TEST_F(DeviceCommandRunRoutineJobTest, RunDiskReadRoutineInvalidFileSizeMb) {
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest, RunPrimeSearchRoutineSuccess) {
// Test that the routine succeeds with all parameters specified.
auto run_routine_response =
chromeos::cros_healthd::mojom::RunRoutineResponse::New(kId, kStatus);
chromeos::cros_healthd::FakeCrosHealthdClient::Get()
->SetRunRoutineResponseForTesting(run_routine_response);
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kLengthSecondsFieldName,
/*length_seconds=*/2342);
params_dict.SetIntKey(kMaxNumFieldName,
/*max_num=*/100000);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(
job.get(), kUniqueID, test_start_time_, base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kPrimeSearch,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::SUCCEEDED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateSuccessPayload(kId, kStatus), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest,
RunPrimeSearchRoutineMissingLengthSeconds) {
// Test that leaving out the length_seconds parameter causes the routine to
// fail.
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kMaxNumFieldName,
/*max_num=*/100000);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(
job.get(), kUniqueID, test_start_time_, base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kPrimeSearch,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::FAILED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateInvalidParametersFailurePayload(), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest, RunPrimeSearchRoutineMissingMaxNum) {
// Test that leaving out the max_num parameter causes the routine to fail.
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kLengthSecondsFieldName,
/*length_seconds=*/2342);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(
job.get(), kUniqueID, test_start_time_, base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kPrimeSearch,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::FAILED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateInvalidParametersFailurePayload(), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest,
RunPrimeSearchRoutineInvalidLengthSeconds) {
// Test that an invalid value for the length_seconds parameter causes the
// routine to fail.
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kLengthSecondsFieldName,
/*length_seconds=*/-1);
params_dict.SetIntKey(kMaxNumFieldName,
/*max_num=*/100000);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(
job.get(), kUniqueID, test_start_time_, base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kPrimeSearch,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::FAILED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateInvalidParametersFailurePayload(), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest, RunPrimeSearchRoutineInvalidMaxNum) {
// Test that an invalid value for the max_num parameter causes the
// routine to fail.
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kLengthSecondsFieldName,
/*length_seconds=*/2342);
params_dict.SetIntKey(kMaxNumFieldName,
/*max_num=*/-1);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(
job.get(), kUniqueID, test_start_time_, base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kPrimeSearch,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::FAILED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateInvalidParametersFailurePayload(), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
} // namespace policy

@ -108,6 +108,13 @@ void FakeCrosHealthdService::RunDiskReadRoutine(
std::move(callback).Run(run_routine_response_.Clone());
}
void FakeCrosHealthdService::RunPrimeSearchRoutine(
uint32_t length_seconds,
uint64_t max_num,
RunPrimeSearchRoutineCallback callback) {
std::move(callback).Run(run_routine_response_.Clone());
}
void FakeCrosHealthdService::ProbeTelemetryInfo(
const std::vector<mojom::ProbeCategoryEnum>& categories,
ProbeTelemetryInfoCallback callback) {

@ -70,6 +70,9 @@ class FakeCrosHealthdService final
uint32_t length_seconds,
uint32_t file_size_mb,
RunDiskReadRoutineCallback callback) override;
void RunPrimeSearchRoutine(uint32_t length_seconds,
uint64_t max_num,
RunPrimeSearchRoutineCallback callback) override;
// CrosHealthdProbeService overrides:
void ProbeTelemetryInfo(

@ -84,6 +84,11 @@ class ServiceConnectionImpl : public ServiceConnection {
uint32_t file_size_mb,
mojom::CrosHealthdDiagnosticsService::RunDiskReadRoutineCallback callback)
override;
void RunPrimeSearchRoutine(
base::TimeDelta& exec_duration,
uint64_t max_num,
mojom::CrosHealthdDiagnosticsService::RunPrimeSearchRoutineCallback
callback) override;
void ProbeTelemetryInfo(
const std::vector<mojom::ProbeCategoryEnum>& categories_to_test,
mojom::CrosHealthdProbeService::ProbeTelemetryInfoCallback callback)
@ -251,6 +256,17 @@ void ServiceConnectionImpl::RunDiskReadRoutine(
type, exec_duration.InSeconds(), file_size_mb, std::move(callback));
}
void ServiceConnectionImpl::RunPrimeSearchRoutine(
base::TimeDelta& exec_duration,
uint64_t max_num,
mojom::CrosHealthdDiagnosticsService::RunPrimeSearchRoutineCallback
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
BindCrosHealthdDiagnosticsServiceIfNeeded();
cros_healthd_diagnostics_service_->RunPrimeSearchRoutine(
exec_duration.InSeconds(), max_num, std::move(callback));
}
void ServiceConnectionImpl::ProbeTelemetryInfo(
const std::vector<mojom::ProbeCategoryEnum>& categories_to_test,
mojom::CrosHealthdProbeService::ProbeTelemetryInfoCallback callback) {

@ -131,6 +131,15 @@ class ServiceConnection {
mojom::CrosHealthdDiagnosticsService::RunDiskReadRoutineCallback
callback) = 0;
// Requests that cros_healthd runs the prime search routine. See
// src/chromeos/service/cros_healthd/public/mojom/cros_healthd.mojom for
// details.
virtual void RunPrimeSearchRoutine(
base::TimeDelta& exec_duration,
uint64_t max_num,
mojom::CrosHealthdDiagnosticsService::RunPrimeSearchRoutineCallback
callback) = 0;
// Gather pieces of information about the platform. See
// src/chromeos/service/cros_healthd/public/mojom/cros_healthd.mojom for
// details.

@ -385,6 +385,21 @@ TEST_F(CrosHealthdServiceConnectionTest, RunDiskReadRoutine) {
run_loop.Run();
}
TEST_F(CrosHealthdServiceConnectionTest, RunPrimeSearchRoutine) {
// Test that we can run the prime search routine.
auto response = MakeRunRoutineResponse();
FakeCrosHealthdClient::Get()->SetRunRoutineResponseForTesting(response);
base::RunLoop run_loop;
base::TimeDelta exec_duration = base::TimeDelta().FromSeconds(10);
ServiceConnection::GetInstance()->RunPrimeSearchRoutine(
/*exec_duration=*/exec_duration, /*max_num=*/1000000,
base::BindLambdaForTesting([&](mojom::RunRoutineResponsePtr response) {
EXPECT_EQ(response, MakeRunRoutineResponse());
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(CrosHealthdServiceConnectionTest, ProbeTelemetryInfo) {
// Test that we can send a request without categories.
auto empty_info = mojom::TelemetryInfo::New();

@ -227,6 +227,24 @@ interface CrosHealthdDiagnosticsService {
RunDiskReadRoutine(DiskReadRoutineTypeEnum type, uint32 length_seconds,
uint32 file_size_mb)
=> (RunRoutineResponse response);
// Requests that the PrimeSearch routine is created and started on the
// platform. Calculate prime numbers between 3 to max_num and verify the
// calculation repeatedly in a duration. This routine is only available
// if GetAvailableRoutines returned kPrimeSearch.
//
// The request:
// * |length_seconds| - length of time, in seconds, to run the PrimeSearch
// routine for. This parameter needs to be strictly
// greater than zero.
// * |max_num| - largest number that routine will calculate prime numbers up
// to.
//
// The response:
// * |response| - contains a unique identifier and status for the created
// routine.
RunPrimeSearchRoutine(uint32 length_seconds, uint64 max_num)
=> (RunRoutineResponse response);
};
// Probe interface exposed by the cros_healthd daemon.

@ -27,6 +27,7 @@ enum DiagnosticRoutineEnum {
kNvmeWearLevel = 8,
kNvmeSelfTest = 9,
kDiskRead = 10,
kPrimeSearch = 11,
};
// Enumeration of the possible DiskRead routine's command type