blob: 1516abf09249980921868a96f02988e8070bb287 [file] [log] [blame]
// Copyright 2019 The Chromium OS 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 <limits>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
#include <base/bind.h>
#include <base/callback.h>
#include <base/run_loop.h>
#include <base/test/task_environment.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "diagnostics/wilco_dtc_supportd/fake_diagnostics_service.h"
#include "diagnostics/wilco_dtc_supportd/routine_service.h"
#include "mojo/cros_healthd_diagnostics.mojom.h"
using testing::ElementsAreArray;
namespace diagnostics {
namespace mojo_ipc = ::chromeos::cros_healthd::mojom;
namespace {
grpc_api::RunRoutineRequest MakeBatteryRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_BATTERY);
request.mutable_battery_params()->set_low_mah(10);
request.mutable_battery_params()->set_high_mah(100);
return request;
}
grpc_api::RunRoutineRequest MakeDefaultBatteryRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_BATTERY);
request.mutable_battery_params();
return request;
}
grpc_api::RunRoutineRequest MakeBatterySysfsRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_BATTERY_SYSFS);
request.mutable_battery_sysfs_params()->set_maximum_cycle_count(2);
request.mutable_battery_sysfs_params()->set_percent_battery_wear_allowed(30);
return request;
}
grpc_api::RunRoutineRequest MakeUrandomRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_URANDOM);
request.mutable_urandom_params()->set_length_seconds(10);
return request;
}
grpc_api::RunRoutineRequest MakeSmartctlCheckRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_SMARTCTL_CHECK);
request.mutable_smartctl_check_params();
return request;
}
grpc_api::RunRoutineRequest MakeCpuCacheRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_CPU_CACHE);
request.mutable_cpu_params()->set_length_seconds(10);
return request;
}
grpc_api::RunRoutineRequest MakeCpuStressRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_CPU_STRESS);
request.mutable_cpu_params()->set_length_seconds(300);
return request;
}
grpc_api::RunRoutineRequest MakeFloatingPointAccuracyRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_FLOATING_POINT_ACCURACY);
request.mutable_floating_point_accuracy_params()->set_length_seconds(2);
return request;
}
grpc_api::RunRoutineRequest MakeNvmeWearLevelRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_NVME_WEAR_LEVEL);
request.mutable_nvme_wear_level_params()->set_wear_level_threshold(50);
return request;
}
grpc_api::RunRoutineRequest MakeNvmeSelfTestShortRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_NVME_SHORT_SELF_TEST);
request.mutable_nvme_short_self_test_params();
return request;
}
grpc_api::RunRoutineRequest MakeNvmeSelfTestLongRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_NVME_LONG_SELF_TEST);
request.mutable_nvme_long_self_test_params();
return request;
}
grpc_api::RunRoutineRequest MakeDiskLinearReadRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_DISK_LINEAR_READ);
request.mutable_disk_linear_read_params()->set_length_seconds(10);
request.mutable_disk_linear_read_params()->set_file_size_mb(1024);
return request;
}
grpc_api::RunRoutineRequest MakeDiskRandomReadRoutineRequest() {
grpc_api::RunRoutineRequest request;
request.set_routine(grpc_api::ROUTINE_DISK_RANDOM_READ);
request.mutable_disk_random_read_params()->set_length_seconds(10);
request.mutable_disk_random_read_params()->set_file_size_mb(1024);
return request;
}
void SaveGetAvailableRoutinesResponse(
base::Closure callback,
grpc_api::GetAvailableRoutinesResponse* response,
const std::vector<grpc_api::DiagnosticRoutine>& returned_routines,
grpc_api::RoutineServiceStatus service_status) {
for (const auto& routine : returned_routines)
response->add_routines(routine);
response->set_service_status(service_status);
callback.Run();
}
void SaveRunRoutineResponse(base::Closure callback,
grpc_api::RunRoutineResponse* response,
int uuid,
grpc_api::DiagnosticRoutineStatus status,
grpc_api::RoutineServiceStatus service_status) {
response->set_uuid(uuid);
response->set_status(status);
response->set_service_status(service_status);
callback.Run();
}
void SaveGetRoutineUpdateResponse(
base::Closure callback,
grpc_api::GetRoutineUpdateResponse* response,
int uuid,
grpc_api::DiagnosticRoutineStatus status,
int progress_percent,
grpc_api::DiagnosticRoutineUserMessage user_message,
const std::string& output,
const std::string& status_message,
grpc_api::RoutineServiceStatus service_status) {
response->set_uuid(uuid);
response->set_status(status);
response->set_progress_percent(progress_percent);
response->set_user_message(user_message);
response->set_output(output);
response->set_status_message(status_message);
response->set_service_status(service_status);
callback.Run();
}
// Tests for the RoutineService class.
class RoutineServiceTest : public testing::Test {
protected:
RoutineServiceTest() = default;
FakeDiagnosticsService* diagnostics_service() {
return &diagnostics_service_;
}
grpc_api::GetAvailableRoutinesResponse ExecuteGetAvailableRoutines() {
base::RunLoop run_loop;
grpc_api::GetAvailableRoutinesResponse response;
service_.GetAvailableRoutines(base::Bind(
&SaveGetAvailableRoutinesResponse, run_loop.QuitClosure(), &response));
run_loop.Run();
return response;
}
grpc_api::RunRoutineResponse ExecuteRunRoutine(
const grpc_api::RunRoutineRequest& request) {
base::RunLoop run_loop;
grpc_api::RunRoutineResponse response;
service_.RunRoutine(request, base::Bind(&SaveRunRoutineResponse,
run_loop.QuitClosure(), &response));
run_loop.Run();
return response;
}
grpc_api::GetRoutineUpdateResponse ExecuteGetRoutineUpdate(
const int uuid,
const grpc_api::GetRoutineUpdateRequest::Command command,
const bool include_output) {
base::RunLoop run_loop;
grpc_api::GetRoutineUpdateResponse response;
service_.GetRoutineUpdate(uuid, command, include_output,
base::Bind(&SaveGetRoutineUpdateResponse,
run_loop.QuitClosure(), &response));
run_loop.Run();
return response;
}
private:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY};
FakeDiagnosticsService diagnostics_service_;
RoutineService service_{&diagnostics_service_};
};
// Test that GetAvailableRoutines returns the expected list of routines.
TEST_F(RoutineServiceTest, GetAvailableRoutines) {
diagnostics_service()->SetGetAvailableRoutinesResponse(
{mojo_ipc::DiagnosticRoutineEnum::kBatteryCapacity,
mojo_ipc::DiagnosticRoutineEnum::kBatteryHealth,
mojo_ipc::DiagnosticRoutineEnum::kSmartctlCheck,
mojo_ipc::DiagnosticRoutineEnum::kUrandom,
mojo_ipc::DiagnosticRoutineEnum::kCpuCache,
mojo_ipc::DiagnosticRoutineEnum::kCpuStress,
mojo_ipc::DiagnosticRoutineEnum::kFloatingPointAccuracy,
mojo_ipc::DiagnosticRoutineEnum::kNvmeWearLevel,
mojo_ipc::DiagnosticRoutineEnum::kNvmeSelfTest,
mojo_ipc::DiagnosticRoutineEnum::kDiskRead});
const auto reply = ExecuteGetAvailableRoutines();
EXPECT_THAT(reply.routines(),
ElementsAreArray(
{grpc_api::ROUTINE_BATTERY, grpc_api::ROUTINE_BATTERY_SYSFS,
grpc_api::ROUTINE_SMARTCTL_CHECK, grpc_api::ROUTINE_URANDOM,
grpc_api::ROUTINE_CPU_CACHE, grpc_api::ROUTINE_CPU_STRESS,
grpc_api::ROUTINE_FLOATING_POINT_ACCURACY,
grpc_api::ROUTINE_NVME_WEAR_LEVEL,
grpc_api::ROUTINE_NVME_SHORT_SELF_TEST,
grpc_api::ROUTINE_NVME_LONG_SELF_TEST,
grpc_api::ROUTINE_DISK_LINEAR_READ,
grpc_api::ROUTINE_DISK_RANDOM_READ}));
EXPECT_EQ(reply.service_status(), grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that an unknown mojo routine enum is handled sanely.
TEST_F(RoutineServiceTest, GetAvailableRoutinesInvalidMojoRoutineEnum) {
diagnostics_service()->SetGetAvailableRoutinesResponse(
std::vector<mojo_ipc::DiagnosticRoutineEnum>{
static_cast<mojo_ipc::DiagnosticRoutineEnum>(
std::numeric_limits<std::underlying_type<
mojo_ipc::DiagnosticRoutineEnum>::type>::max()),
mojo_ipc::DiagnosticRoutineEnum::kBatteryCapacity});
const auto reply = ExecuteGetAvailableRoutines();
EXPECT_THAT(reply.routines(), ElementsAreArray({grpc_api::ROUTINE_BATTERY}));
EXPECT_EQ(reply.service_status(), grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that an invalid RunRoutineRequest is handled sanely.
TEST_F(RoutineServiceTest, InvalidRunRoutineRequest) {
grpc_api::RunRoutineRequest request;
request.set_routine(static_cast<grpc_api::DiagnosticRoutine>(
std::numeric_limits<
std::underlying_type<grpc_api::DiagnosticRoutine>::type>::max()));
const auto reply = ExecuteRunRoutine(request);
EXPECT_EQ(reply.uuid(), 0);
EXPECT_EQ(reply.status(), grpc_api::ROUTINE_STATUS_INVALID_FIELD);
EXPECT_EQ(reply.service_status(), grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that a routine reporting an invalid user message is handled sanely.
TEST_F(RoutineServiceTest, GetRoutineUpdateInvalidUserMessage) {
diagnostics_service()->SetInteractiveUpdate(
static_cast<mojo_ipc::DiagnosticRoutineUserMessageEnum>(
std::numeric_limits<std::underlying_type<
mojo_ipc::DiagnosticRoutineUserMessageEnum>::type>::max()),
0 /* progress_percent */, "" /* output */);
const auto update_response = ExecuteGetRoutineUpdate(
0 /* uuid */, grpc_api::GetRoutineUpdateRequest::GET_STATUS,
false /* include_output */);
EXPECT_EQ(update_response.status(), grpc_api::ROUTINE_STATUS_ERROR);
EXPECT_EQ(update_response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that a routine update reporting an invalid status is handled sanely.
TEST_F(RoutineServiceTest, InvalidGetRoutineUpdateStatus) {
diagnostics_service()->SetNonInteractiveUpdate(
static_cast<mojo_ipc::DiagnosticRoutineStatusEnum>(
std::numeric_limits<std::underlying_type<
mojo_ipc::DiagnosticRoutineStatusEnum>::type>::max()),
"" /* status_message */, 0 /* progress_percent */, "" /* output */);
const auto update_response = ExecuteGetRoutineUpdate(
0 /* uuid */, grpc_api::GetRoutineUpdateRequest::GET_STATUS,
false /* include_output */);
EXPECT_EQ(update_response.status(), grpc_api::ROUTINE_STATUS_ERROR);
EXPECT_EQ(update_response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that a run routine response reporting an invalid status is handled
// sanely.
TEST_F(RoutineServiceTest, InvalidRunRoutineResponseStatus) {
diagnostics_service()->SetRunSomeRoutineResponse(
0 /* uuid */,
static_cast<mojo_ipc::DiagnosticRoutineStatusEnum>(
std::numeric_limits<std::underlying_type<
mojo_ipc::DiagnosticRoutineStatusEnum>::type>::max()));
const auto response = ExecuteRunRoutine(MakeSmartctlCheckRoutineRequest());
EXPECT_EQ(response.status(), grpc_api::ROUTINE_STATUS_ERROR);
EXPECT_EQ(response.uuid(), 0);
EXPECT_EQ(response.service_status(), grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that an invalid command passed to the routine service is handled sanely.
TEST_F(RoutineServiceTest, GetRoutineUpdateInvalidCommand) {
diagnostics_service()->SetNonInteractiveUpdate(
mojo_ipc::DiagnosticRoutineStatusEnum::kReady, "" /* status_message */,
0 /* progress_percent */, "" /* output */);
const auto update_response = ExecuteGetRoutineUpdate(
0 /* uuid */,
static_cast<grpc_api::GetRoutineUpdateRequest::Command>(
std::numeric_limits<std::underlying_type<
grpc_api::GetRoutineUpdateRequest::Command>::type>::max()),
false /* include_output */);
EXPECT_EQ(update_response.status(), grpc_api::ROUTINE_STATUS_INVALID_FIELD);
EXPECT_EQ(update_response.progress_percent(), 0);
EXPECT_EQ(update_response.user_message(),
grpc_api::ROUTINE_USER_MESSAGE_UNSET);
EXPECT_EQ(update_response.output(), "");
EXPECT_EQ(update_response.status_message(), "");
EXPECT_EQ(update_response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that the routine service doesn't attempt to rebind a valid mojo service
// pointer.
TEST_F(RoutineServiceTest, NoRebindService) {
constexpr uint32_t kExpectedId = 55;
diagnostics_service()->SetRunSomeRoutineResponse(
kExpectedId, mojo_ipc::DiagnosticRoutineStatusEnum::kRunning);
// Send the first mojo IPC to the diagnostics service. This IPC should
// bootstrap the mojo connection. Ignore the response, because we're only
// interested in whether or not the next request tries to bootstrap the mojo
// connection again.
ExecuteRunRoutine(MakeSmartctlCheckRoutineRequest());
// Tell the service to respond with an error if a second bootstrapping is
// requested.
diagnostics_service()->SetMojoServiceIsAvailable(false);
// Send another request. This shouldn't see an error, because it shouldn't try
// to bootstrap the mojo connection a second time.
const auto reply = ExecuteRunRoutine(MakeSmartctlCheckRoutineRequest());
// If the bootstrap was requested a second time, we would receive a uuid of 0
// and a status of grpc_api::FAILED_TO_START.
EXPECT_EQ(reply.uuid(), kExpectedId);
EXPECT_EQ(reply.status(), grpc_api::ROUTINE_STATUS_RUNNING);
EXPECT_EQ(reply.service_status(), grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that the routine service handles a GetAvailableRoutines request sent
// before wilco_dtc_supportd's mojo service is established.
TEST_F(RoutineServiceTest, GetAvailableRoutinesNoService) {
diagnostics_service()->SetMojoServiceIsAvailable(false);
const auto reply = ExecuteGetAvailableRoutines();
EXPECT_EQ(reply.routines_size(), 0);
EXPECT_EQ(reply.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_UNAVAILABLE);
}
// Test that the routine service handles a RunRoutine request sent before
// wilco_dtc_supportd's mojo service is established.
TEST_F(RoutineServiceTest, RunRoutineNoService) {
diagnostics_service()->SetMojoServiceIsAvailable(false);
const auto response = ExecuteRunRoutine(MakeSmartctlCheckRoutineRequest());
EXPECT_EQ(response.status(), grpc_api::ROUTINE_STATUS_FAILED_TO_START);
EXPECT_EQ(response.uuid(), 0);
EXPECT_EQ(response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_UNAVAILABLE);
}
// Test that the routine service handles a GetRoutineUpdate request sent before
// wilco_dtc_supportd's mojo service is established.
TEST_F(RoutineServiceTest, GetRoutineUpdateNoService) {
diagnostics_service()->SetMojoServiceIsAvailable(false);
const auto update_response = ExecuteGetRoutineUpdate(
0 /* uuid */, grpc_api::GetRoutineUpdateRequest::GET_STATUS,
false /* include_output */);
EXPECT_EQ(update_response.status(), grpc_api::ROUTINE_STATUS_ERROR);
EXPECT_EQ(update_response.progress_percent(), 0);
EXPECT_EQ(update_response.user_message(),
grpc_api::ROUTINE_USER_MESSAGE_UNSET);
EXPECT_EQ(update_response.output(), "");
EXPECT_EQ(update_response.status_message(), "");
EXPECT_EQ(update_response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_UNAVAILABLE);
}
// Test that the routine service can recover from an early gRPC request if
// wilco_dtc_supportd's mojo service is established later.
TEST_F(RoutineServiceTest, RecoverFromNoServiceRequest) {
// Deal with a request sent before the mojo service is available.
diagnostics_service()->SetMojoServiceIsAvailable(false);
const auto unavailable_reply = ExecuteGetAvailableRoutines();
EXPECT_EQ(unavailable_reply.routines_size(), 0);
EXPECT_EQ(unavailable_reply.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_UNAVAILABLE);
base::RunLoop().RunUntilIdle();
// Make the mojo service available, and make sure a valid response is
// received.
diagnostics_service()->SetMojoServiceIsAvailable(true);
diagnostics_service()->SetGetAvailableRoutinesResponse(
{mojo_ipc::DiagnosticRoutineEnum::kBatteryCapacity,
mojo_ipc::DiagnosticRoutineEnum::kBatteryHealth,
mojo_ipc::DiagnosticRoutineEnum::kSmartctlCheck,
mojo_ipc::DiagnosticRoutineEnum::kUrandom,
mojo_ipc::DiagnosticRoutineEnum::kCpuCache,
mojo_ipc::DiagnosticRoutineEnum::kCpuStress,
mojo_ipc::DiagnosticRoutineEnum::kFloatingPointAccuracy,
mojo_ipc::DiagnosticRoutineEnum::kNvmeWearLevel,
mojo_ipc::DiagnosticRoutineEnum::kNvmeSelfTest,
mojo_ipc::DiagnosticRoutineEnum::kDiskRead});
const auto reply = ExecuteGetAvailableRoutines();
EXPECT_THAT(reply.routines(),
ElementsAreArray(
{grpc_api::ROUTINE_BATTERY, grpc_api::ROUTINE_BATTERY_SYSFS,
grpc_api::ROUTINE_SMARTCTL_CHECK, grpc_api::ROUTINE_URANDOM,
grpc_api::ROUTINE_CPU_CACHE, grpc_api::ROUTINE_CPU_STRESS,
grpc_api::ROUTINE_FLOATING_POINT_ACCURACY,
grpc_api::ROUTINE_NVME_WEAR_LEVEL,
grpc_api::ROUTINE_NVME_SHORT_SELF_TEST,
grpc_api::ROUTINE_NVME_LONG_SELF_TEST,
grpc_api::ROUTINE_DISK_LINEAR_READ,
grpc_api::ROUTINE_DISK_RANDOM_READ}));
EXPECT_EQ(reply.service_status(), grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Test that the routine service handles a GetAvailableRoutines request sent
// when cros_healthd is unresponsive.
TEST_F(RoutineServiceTest, GetAvailableRoutinesUnresponsiveService) {
diagnostics_service()->SetMojoServiceIsResponsive(false);
const auto reply = ExecuteGetAvailableRoutines();
EXPECT_EQ(reply.routines_size(), 0);
EXPECT_EQ(reply.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_UNAVAILABLE);
}
// Test that the routine service handles a RunRoutine request sent when
// cros_healthd is unresponsive.
TEST_F(RoutineServiceTest, RunRoutineUnresponsiveService) {
diagnostics_service()->SetMojoServiceIsResponsive(false);
const auto response = ExecuteRunRoutine(MakeSmartctlCheckRoutineRequest());
EXPECT_EQ(response.status(), grpc_api::ROUTINE_STATUS_FAILED_TO_START);
EXPECT_EQ(response.uuid(), 0);
EXPECT_EQ(response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_UNAVAILABLE);
}
// Test that the routine service handles a GetRoutineUpdate request sent when
// cros_healthd is unresponsive.
TEST_F(RoutineServiceTest, GetRoutineUpdateUnresponsiveService) {
diagnostics_service()->SetMojoServiceIsResponsive(false);
constexpr int kUuid = 11;
const auto update_response = ExecuteGetRoutineUpdate(
kUuid, grpc_api::GetRoutineUpdateRequest::GET_STATUS,
false /* include_output */);
EXPECT_EQ(update_response.uuid(), kUuid);
EXPECT_EQ(update_response.status(), grpc_api::ROUTINE_STATUS_ERROR);
EXPECT_EQ(update_response.progress_percent(), 0);
EXPECT_EQ(update_response.user_message(),
grpc_api::ROUTINE_USER_MESSAGE_UNSET);
EXPECT_EQ(update_response.output(), "");
EXPECT_EQ(update_response.status_message(), "");
EXPECT_EQ(update_response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_UNAVAILABLE);
}
// Test that the routine service can recover from a dropped connection.
TEST_F(RoutineServiceTest, RecoverFromDroppedConnection) {
// Establish a valid connection.
diagnostics_service()->SetGetAvailableRoutinesResponse(
{mojo_ipc::DiagnosticRoutineEnum::kBatteryCapacity,
mojo_ipc::DiagnosticRoutineEnum::kBatteryHealth,
mojo_ipc::DiagnosticRoutineEnum::kSmartctlCheck,
mojo_ipc::DiagnosticRoutineEnum::kUrandom,
mojo_ipc::DiagnosticRoutineEnum::kCpuCache,
mojo_ipc::DiagnosticRoutineEnum::kCpuStress,
mojo_ipc::DiagnosticRoutineEnum::kFloatingPointAccuracy,
mojo_ipc::DiagnosticRoutineEnum::kNvmeWearLevel,
mojo_ipc::DiagnosticRoutineEnum::kNvmeSelfTest,
mojo_ipc::DiagnosticRoutineEnum::kDiskRead});
const auto reply = ExecuteGetAvailableRoutines();
EXPECT_THAT(reply.routines(),
ElementsAreArray(
{grpc_api::ROUTINE_BATTERY, grpc_api::ROUTINE_BATTERY_SYSFS,
grpc_api::ROUTINE_SMARTCTL_CHECK, grpc_api::ROUTINE_URANDOM,
grpc_api::ROUTINE_CPU_CACHE, grpc_api::ROUTINE_CPU_STRESS,
grpc_api::ROUTINE_FLOATING_POINT_ACCURACY,
grpc_api::ROUTINE_NVME_WEAR_LEVEL,
grpc_api::ROUTINE_NVME_SHORT_SELF_TEST,
grpc_api::ROUTINE_NVME_LONG_SELF_TEST,
grpc_api::ROUTINE_DISK_LINEAR_READ,
grpc_api::ROUTINE_DISK_RANDOM_READ}));
EXPECT_EQ(reply.service_status(), grpc_api::ROUTINE_SERVICE_STATUS_OK);
// Reset the connection, make cros_healthd unresponsive, and check to see that
// the routine service responds appropriately.
diagnostics_service()->ResetMojoConnection();
diagnostics_service()->SetMojoServiceIsResponsive(false);
const auto dropped_reply = ExecuteGetAvailableRoutines();
EXPECT_EQ(dropped_reply.routines_size(), 0);
EXPECT_EQ(dropped_reply.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_UNAVAILABLE);
// Set cros_healthd as available again, and make sure the routine service can
// get valid responses.
diagnostics_service()->SetMojoServiceIsResponsive(true);
constexpr uint32_t kExpectedId = 77;
diagnostics_service()->SetRunSomeRoutineResponse(
kExpectedId, mojo_ipc::DiagnosticRoutineStatusEnum::kRunning);
const auto reconnected_reply =
ExecuteRunRoutine(MakeSmartctlCheckRoutineRequest());
EXPECT_EQ(reconnected_reply.uuid(), kExpectedId);
EXPECT_EQ(reconnected_reply.status(), grpc_api::ROUTINE_STATUS_RUNNING);
EXPECT_EQ(reconnected_reply.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
// Tests for the GetRoutineUpdate() method of RoutineService when an
// interactive update is returned.
//
// This is a parameterized test with the following parameters:
// * |mojo_message| - mojo's DiagnosticRoutineUserMessageEnum returned in the
// routine's update.
// * |grpc_message| - gRPC's DiagnosticRoutineUserMessage expected to be
// returned by the routine service.
class GetInteractiveUpdateTest
: public RoutineServiceTest,
public testing::WithParamInterface<
std::tuple<mojo_ipc::DiagnosticRoutineUserMessageEnum,
grpc_api::DiagnosticRoutineUserMessage>> {
protected:
// Accessors to individual test parameters from the test parameter tuple
// returned by gtest's GetParam():
mojo_ipc::DiagnosticRoutineUserMessageEnum mojo_message() const {
return std::get<0>(GetParam());
}
grpc_api::DiagnosticRoutineUserMessage grpc_message() const {
return std::get<1>(GetParam());
}
};
// Test that after a routine has started, we can access its interactive data.
TEST_P(GetInteractiveUpdateTest, AccessInteractiveRunningRoutine) {
constexpr uint32_t kExpectedProgressPercent = 17;
constexpr char kExpectedOutput[] = "Expected output.";
diagnostics_service()->SetInteractiveUpdate(
mojo_message(), kExpectedProgressPercent, kExpectedOutput);
const auto update_response = ExecuteGetRoutineUpdate(
0 /* uuid */, grpc_api::GetRoutineUpdateRequest::GET_STATUS,
true /* include_output */);
EXPECT_EQ(update_response.user_message(), grpc_message());
EXPECT_EQ(update_response.progress_percent(), kExpectedProgressPercent);
EXPECT_EQ(update_response.output(), kExpectedOutput);
EXPECT_EQ(update_response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
INSTANTIATE_TEST_SUITE_P(
,
GetInteractiveUpdateTest,
testing::Values(std::make_tuple(
mojo_ipc::DiagnosticRoutineUserMessageEnum::kUnplugACPower,
grpc_api::ROUTINE_USER_MESSAGE_UNPLUG_AC_POWER)));
// Tests for the GetRoutineUpdate() method of RoutineService when a
// noninteractive update is returned.
//
// This is a parameterized test with the following parameters:
// * |mojo_status| - mojo's DiagnosticRoutineStatusEnum returned in the
// routine's update.
// * |grpc_status| - gRPC's DiagnosticRoutineStatus expected to be
// returned by the routine service.
class GetNonInteractiveUpdateTest
: public RoutineServiceTest,
public testing::WithParamInterface<
std::tuple<mojo_ipc::DiagnosticRoutineStatusEnum,
grpc_api::DiagnosticRoutineStatus>> {
protected:
// Accessors to individual test parameters from the test parameter tuple
// returned by gtest's GetParam():
mojo_ipc::DiagnosticRoutineStatusEnum mojo_status() const {
return std::get<0>(GetParam());
}
grpc_api::DiagnosticRoutineStatus grpc_status() const {
return std::get<1>(GetParam());
}
};
// Test that after a routine has started, we can access its noninteractive data.
TEST_P(GetNonInteractiveUpdateTest, AccessNonInteractiveRunningRoutine) {
constexpr char kExpectedStatusMessage[] = "Expected status message.";
constexpr uint32_t kExpectedProgressPercent = 18;
constexpr char kExpectedOutput[] = "Expected output.";
diagnostics_service()->SetNonInteractiveUpdate(
mojo_status(), kExpectedStatusMessage, kExpectedProgressPercent,
kExpectedOutput);
const auto update_response = ExecuteGetRoutineUpdate(
0 /* uuid */, grpc_api::GetRoutineUpdateRequest::GET_STATUS,
true /* include_output */);
EXPECT_EQ(update_response.status(), grpc_status());
EXPECT_EQ(update_response.status_message(), kExpectedStatusMessage);
EXPECT_EQ(update_response.progress_percent(), kExpectedProgressPercent);
EXPECT_EQ(update_response.output(), kExpectedOutput);
EXPECT_EQ(update_response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
INSTANTIATE_TEST_SUITE_P(
,
GetNonInteractiveUpdateTest,
testing::Values(
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kReady,
grpc_api::ROUTINE_STATUS_READY),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kRunning,
grpc_api::ROUTINE_STATUS_RUNNING),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kWaiting,
grpc_api::ROUTINE_STATUS_WAITING),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kPassed,
grpc_api::ROUTINE_STATUS_PASSED),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kFailed,
grpc_api::ROUTINE_STATUS_FAILED),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kError,
grpc_api::ROUTINE_STATUS_ERROR),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kCancelled,
grpc_api::ROUTINE_STATUS_CANCELLED),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kFailedToStart,
grpc_api::ROUTINE_STATUS_FAILED_TO_START),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kRemoved,
grpc_api::ROUTINE_STATUS_REMOVED),
std::make_tuple(mojo_ipc::DiagnosticRoutineStatusEnum::kCancelling,
grpc_api::ROUTINE_STATUS_CANCELLING)));
// Tests for the GetRoutineUpdate() method of RoutineService with different
// commands.
//
// This is a parameterized test with the following parameters:
// * |command| - gRPC's GetRoutineUpdateRequest::Command included in the
// GetRoutineUpdateRequest.
class GetRoutineUpdateCommandTest
: public RoutineServiceTest,
public testing::WithParamInterface<
grpc_api::GetRoutineUpdateRequest::Command> {
protected:
// Accessors to the test parameter returned by gtest's GetParam():
grpc_api::GetRoutineUpdateRequest::Command command() const {
return GetParam();
}
};
// Test that we can send the given command.
TEST_P(GetRoutineUpdateCommandTest, SendCommand) {
constexpr char kExpectedStatusMessage[] = "Expected status message.";
constexpr uint32_t kExpectedProgressPercent = 19;
constexpr char kExpectedOutput[] = "Expected output.";
constexpr mojo_ipc::DiagnosticRoutineStatusEnum kMojoStatus =
mojo_ipc::DiagnosticRoutineStatusEnum::kRunning;
constexpr grpc_api::DiagnosticRoutineStatus kExpectedStatus =
grpc_api::ROUTINE_STATUS_RUNNING;
diagnostics_service()->SetNonInteractiveUpdate(
kMojoStatus, kExpectedStatusMessage, kExpectedProgressPercent,
kExpectedOutput);
const auto update_response = ExecuteGetRoutineUpdate(
0 /* uuid */, command(), true /* include_output */);
EXPECT_EQ(update_response.status(), kExpectedStatus);
EXPECT_EQ(update_response.status_message(), kExpectedStatusMessage);
EXPECT_EQ(update_response.progress_percent(), kExpectedProgressPercent);
EXPECT_EQ(update_response.output(), kExpectedOutput);
EXPECT_EQ(update_response.service_status(),
grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
INSTANTIATE_TEST_SUITE_P(
,
GetRoutineUpdateCommandTest,
testing::Values(grpc_api::GetRoutineUpdateRequest::RESUME,
grpc_api::GetRoutineUpdateRequest::CANCEL,
grpc_api::GetRoutineUpdateRequest::REMOVE,
grpc_api::GetRoutineUpdateRequest::GET_STATUS));
// Tests for the RunRoutine() method of RoutineService with different requests.
//
// This is a parameterized test with the following parameters:
// * |request| - gRPC's RunRoutineRequest to be requested.
class RunRoutineTest
: public RoutineServiceTest,
public testing::WithParamInterface<grpc_api::RunRoutineRequest> {
public:
RunRoutineTest() = default;
RunRoutineTest(const RunRoutineTest&) = delete;
RunRoutineTest& operator=(const RunRoutineTest&) = delete;
// Accessors to the test parameter returned by gtest's GetParam():
grpc_api::RunRoutineRequest request() const { return GetParam(); }
};
// Test that we can request that the given routine is run.
TEST_P(RunRoutineTest, RunRoutine) {
constexpr uint32_t kExpectedId = 77;
diagnostics_service()->SetRunSomeRoutineResponse(
kExpectedId, mojo_ipc::DiagnosticRoutineStatusEnum::kRunning);
const auto reply = ExecuteRunRoutine(request());
EXPECT_EQ(reply.uuid(), kExpectedId);
EXPECT_EQ(reply.status(), grpc_api::ROUTINE_STATUS_RUNNING);
EXPECT_EQ(reply.service_status(), grpc_api::ROUTINE_SERVICE_STATUS_OK);
}
INSTANTIATE_TEST_SUITE_P(
,
RunRoutineTest,
testing::Values(MakeBatteryRoutineRequest(),
MakeDefaultBatteryRoutineRequest(),
MakeBatterySysfsRoutineRequest(),
MakeUrandomRoutineRequest(),
MakeSmartctlCheckRoutineRequest(),
MakeCpuCacheRoutineRequest(),
MakeCpuStressRoutineRequest(),
MakeFloatingPointAccuracyRoutineRequest(),
MakeNvmeWearLevelRoutineRequest(),
MakeNvmeSelfTestShortRoutineRequest(),
MakeNvmeSelfTestLongRoutineRequest(),
MakeDiskLinearReadRoutineRequest(),
MakeDiskRandomReadRoutineRequest()));
} // namespace
} // namespace diagnostics