Commit 281232ad authored by Harvey Yang's avatar Harvey Yang Committed by Commit Bot

Chromium: Add Fake Classes in chromeos/components/sensors

This commit adds fake classes: FakeSensorService and FakeSensorDevice in
chromeos/components/sensors to add unit tests of sensor clients in
Chromium, such as ash/accelerometer and Generic Sensor.

BUG=chromium:1006141
TEST=unit tests of ash/accelerometer

Change-Id: If4cab4907a3db0e84214ec274ce9dab0a7f2cc44
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2449311
Commit-Queue: Cheng-Hao Yang <chenghaoyang@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815053}
parent bb571b0f
......@@ -21,10 +21,14 @@ component("sensors") {
source_set("test_support") {
testonly = true
sources = [
"fake_sensor_device.cc",
"fake_sensor_device.h",
"fake_sensor_hal_client.cc",
"fake_sensor_hal_client.h",
"fake_sensor_hal_server.cc",
"fake_sensor_hal_server.h",
"fake_sensor_service.cc",
"fake_sensor_service.h",
]
deps = [
":sensors",
......
chenghaoyang@chromium.org
gwendal@chromium.org
hashimoto@chromium.org
// Copyright 2020 The Chromium 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 "chromeos/components/sensors/fake_sensor_device.h"
#include <algorithm>
#include <utility>
#include "base/bind.h"
#include "base/containers/flat_map.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace chromeos {
namespace sensors {
FakeSensorDevice::ChannelData::ChannelData() = default;
FakeSensorDevice::ChannelData::ChannelData(
const FakeSensorDevice::ChannelData&) = default;
FakeSensorDevice::ChannelData& FakeSensorDevice::ChannelData::operator=(
const FakeSensorDevice::ChannelData&) = default;
FakeSensorDevice::ChannelData::~ChannelData() = default;
FakeSensorDevice::FakeSensorDevice() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
FakeSensorDevice::~FakeSensorDevice() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
bool FakeSensorDevice::is_bound() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return receiver_.is_bound();
}
void FakeSensorDevice::Bind(
mojo::PendingReceiver<mojom::SensorDevice> pending_receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!is_bound());
receiver_.Bind(std::move(pending_receiver));
receiver_.set_disconnect_handler(base::BindOnce(
&FakeSensorDevice::OnDeviceDisconnect, base::Unretained(this)));
}
void FakeSensorDevice::OnDeviceDisconnect() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
receiver_.reset();
}
void FakeSensorDevice::SetAttribute(const std::string& attr_name,
const std::string& attr_value) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
attributes_[attr_name] = attr_value;
}
void FakeSensorDevice::SetChannels(const std::vector<ChannelData>& channels) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(channels_.empty());
channels_ = channels;
channels_enabled_.assign(channels_.size(), false);
}
void FakeSensorDevice::GetAttribute(const std::string& attr_name,
GetAttributeCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::Optional<std::string> value = base::nullopt;
auto it = attributes_.find(attr_name);
if (it != attributes_.end())
value = it->second;
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(value)));
}
void FakeSensorDevice::SetFrequency(double frequency,
SetFrequencyCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (frequency < 0.0)
frequency = 0.0;
frequency_ = frequency;
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(frequency)));
if (ReadyToSendSample())
SendSample();
}
void FakeSensorDevice::StartReadingSamples(
mojo::PendingRemote<mojom::SensorDeviceSamplesObserver> observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (observer_.is_bound()) {
mojo::Remote<mojom::SensorDeviceSamplesObserver> remote(
std::move(observer));
remote->OnErrorOccurred(mojom::ObserverErrorType::ALREADY_STARTED);
return;
}
observer_.Bind(std::move(observer));
// Reuse StopReadingSamples to reset |observer_|.
observer_.set_disconnect_handler(base::BindOnce(
&FakeSensorDevice::StopReadingSamples, base::Unretained(this)));
if (!frequency_.has_value() || frequency_.value() <= 0.0) {
observer_->OnErrorOccurred(mojom::ObserverErrorType::FREQUENCY_INVALID);
}
if (!std::any_of(channels_enabled_.begin(), channels_enabled_.end(),
[](bool en) { return en; }))
observer_->OnErrorOccurred(mojom::ObserverErrorType::NO_ENABLED_CHANNELS);
if (ReadyToSendSample())
SendSample();
}
void FakeSensorDevice::StopReadingSamples() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
observer_.reset();
}
void FakeSensorDevice::GetAllChannelIds(GetAllChannelIdsCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<std::string> channel_ids;
for (const ChannelData& channel : channels_)
channel_ids.push_back(channel.id);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(channel_ids)));
}
void FakeSensorDevice::SetChannelsEnabled(
const std::vector<int32_t>& iio_chn_indices,
bool en,
SetChannelsEnabledCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<int32_t> failed_indices;
for (int32_t index : iio_chn_indices) {
if (static_cast<size_t>(index) >= channels_enabled_.size()) {
failed_indices.push_back(index);
continue;
}
channels_enabled_[index] = en;
}
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), std::move(failed_indices)));
if (ReadyToSendSample())
SendSample();
}
void FakeSensorDevice::GetChannelsEnabled(
const std::vector<int32_t>& iio_chn_indices,
GetChannelsEnabledCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<bool> enabled;
for (int32_t index : iio_chn_indices) {
if (static_cast<size_t>(index) >= channels_enabled_.size()) {
enabled.push_back(false);
continue;
}
enabled.push_back(channels_enabled_[index]);
}
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(enabled)));
}
void FakeSensorDevice::GetChannelsAttributes(
const std::vector<int32_t>& iio_chn_indices,
const std::string& attr_name,
GetChannelsAttributesCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<base::Optional<std::string>> attrs;
for (const ChannelData& channel : channels_) {
auto it = channel.attrs.find(attr_name);
if (it == channel.attrs.end()) {
attrs.push_back(base::nullopt);
continue;
}
attrs.push_back(it->second);
}
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(attrs)));
}
bool FakeSensorDevice::ReadyToSendSample() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!observer_.is_bound())
return false;
if (!frequency_.has_value() || frequency_.value() <= 0.0)
return false;
return std::any_of(channels_enabled_.begin(), channels_enabled_.end(),
[](bool en) { return en; });
}
void FakeSensorDevice::SendSample() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(ReadyToSendSample());
CHECK_EQ(channels_.size(), channels_enabled_.size());
base::flat_map<int32_t, int64_t> sample;
for (size_t i = 0; i < channels_.size(); ++i) {
if (!channels_enabled_[i])
continue;
sample[i] = channels_[i].sample_data;
}
observer_->OnSampleUpdated(std::move(sample));
}
} // namespace sensors
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_COMPONENTS_SENSORS_FAKE_SENSOR_DEVICE_H_
#define CHROMEOS_COMPONENTS_SENSORS_FAKE_SENSOR_DEVICE_H_
#include <map>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "chromeos/components/sensors/mojom/sensor.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace chromeos {
namespace sensors {
class FakeSensorDevice final : public mojom::SensorDevice {
public:
struct ChannelData {
ChannelData();
ChannelData(const ChannelData&);
ChannelData& operator=(const ChannelData&);
~ChannelData();
std::string id;
std::map<std::string, std::string> attrs;
int64_t sample_data;
};
FakeSensorDevice();
FakeSensorDevice(const FakeSensorDevice&) = delete;
FakeSensorDevice& operator=(const FakeSensorDevice&) = delete;
~FakeSensorDevice() override;
bool is_bound();
void Bind(mojo::PendingReceiver<mojom::SensorDevice> pending_receiver);
void OnDeviceDisconnect();
void SetAttribute(const std::string& attr_name,
const std::string& attr_value);
void SetChannels(const std::vector<ChannelData>& channels);
// Implementation of mojom::SensorDevice.
void SetTimeout(uint32_t timeout) override {}
void GetAttribute(const std::string& attr_name,
GetAttributeCallback callback) override;
void SetFrequency(double frequency, SetFrequencyCallback callback) override;
void StartReadingSamples(
mojo::PendingRemote<mojom::SensorDeviceSamplesObserver> observer)
override;
void StopReadingSamples() override;
void GetAllChannelIds(GetAllChannelIdsCallback callback) override;
void SetChannelsEnabled(const std::vector<int32_t>& iio_chn_indices,
bool en,
SetChannelsEnabledCallback callback) override;
void GetChannelsEnabled(const std::vector<int32_t>& iio_chn_indices,
GetChannelsEnabledCallback callback) override;
void GetChannelsAttributes(const std::vector<int32_t>& iio_chn_indices,
const std::string& attr_name,
GetChannelsAttributesCallback callback) override;
private:
bool ReadyToSendSample();
void SendSample();
std::map<std::string, std::string> attributes_;
base::Optional<double> frequency_;
std::vector<ChannelData> channels_;
std::vector<bool> channels_enabled_;
mojo::Remote<mojom::SensorDeviceSamplesObserver> observer_;
mojo::Receiver<mojom::SensorDevice> receiver_{this};
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace sensors
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_SENSORS_FAKE_SENSOR_DEVICE_H_
......@@ -17,7 +17,7 @@ void FakeSensorHalClient::SetUpChannel(
}
mojo::PendingRemote<mojom::SensorHalClient> FakeSensorHalClient::PassRemote() {
CHECK(!receiver_.is_bound());
DCHECK(!receiver_.is_bound());
return receiver_.BindNewPipeAndPassRemote();
}
......
......@@ -7,26 +7,31 @@
namespace chromeos {
namespace sensors {
FakeSensorHalServer::FakeSensorHalServer() {}
FakeSensorHalServer::FakeSensorHalServer()
: sensor_service_(new FakeSensorService()) {}
FakeSensorHalServer::~FakeSensorHalServer() = default;
void FakeSensorHalServer::CreateChannel(
mojo::PendingReceiver<mojom::SensorService> sensor_service_receiver) {
DCHECK(!SensorServiceIsValid());
sensor_service_receiver_ = std::move(sensor_service_receiver);
DCHECK(!sensor_service_->is_bound());
sensor_service_->Bind(std::move(sensor_service_receiver));
}
mojo::PendingRemote<mojom::SensorHalServer> FakeSensorHalServer::PassRemote() {
CHECK(!receiver_.is_bound());
return receiver_.BindNewPipeAndPassRemote();
DCHECK(!receiver_.is_bound());
auto pending_remote = receiver_.BindNewPipeAndPassRemote();
receiver_.set_disconnect_handler(base::BindOnce(
&FakeSensorHalServer::OnServerDisconnect, base::Unretained(this)));
return pending_remote;
}
bool FakeSensorHalServer::SensorServiceIsValid() {
return sensor_service_receiver_.is_valid();
void FakeSensorHalServer::OnServerDisconnect() {
receiver_.reset();
}
void FakeSensorHalServer::ResetSensorService() {
sensor_service_receiver_.reset();
FakeSensorService* FakeSensorHalServer::GetSensorService() {
return sensor_service_.get();
}
} // namespace sensors
......
......@@ -5,6 +5,7 @@
#ifndef CHROMEOS_COMPONENTS_SENSORS_FAKE_SENSOR_HAL_SERVER_H_
#define CHROMEOS_COMPONENTS_SENSORS_FAKE_SENSOR_HAL_SERVER_H_
#include "chromeos/components/sensors/fake_sensor_service.h"
#include "chromeos/components/sensors/mojom/cros_sensor_service.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
......@@ -19,16 +20,18 @@ class FakeSensorHalServer : public mojom::SensorHalServer {
FakeSensorHalServer& operator=(const FakeSensorHalServer&) = delete;
~FakeSensorHalServer() override;
// Implementation of mojom::SensorService.
void CreateChannel(mojo::PendingReceiver<mojom::SensorService>
sensor_service_receiver) override;
void OnServerDisconnect();
mojo::PendingRemote<mojom::SensorHalServer> PassRemote();
bool SensorServiceIsValid();
void ResetSensorService();
FakeSensorService* GetSensorService();
private:
mojo::PendingReceiver<mojom::SensorService> sensor_service_receiver_;
std::unique_ptr<FakeSensorService> sensor_service_;
mojo::Receiver<mojom::SensorHalServer> receiver_{this};
};
......
// Copyright 2020 The Chromium 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 "chromeos/components/sensors/fake_sensor_service.h"
#include <utility>
#include "base/bind.h"
#include "base/containers/flat_map.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace chromeos {
namespace sensors {
FakeSensorService::FakeSensorService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
FakeSensorService::~FakeSensorService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
bool FakeSensorService::is_bound() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return receiver_.is_bound();
}
void FakeSensorService::Bind(
mojo::PendingReceiver<mojom::SensorService> pending_receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!is_bound());
receiver_.Bind(std::move(pending_receiver));
receiver_.set_disconnect_handler(base::BindOnce(
&FakeSensorService::OnServiceDisconnect, base::Unretained(this)));
}
void FakeSensorService::OnServiceDisconnect() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
receiver_.reset();
}
void FakeSensorService::SetDevice(
int32_t iio_device_id,
std::set<mojom::DeviceType> types,
std::unique_ptr<FakeSensorDevice> sensor_device) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DeviceData data;
data.types = std::move(types);
data.sensor_device = std::move(sensor_device);
devices_[iio_device_id] = std::move(data);
}
void FakeSensorService::GetDeviceIds(mojom::DeviceType type,
GetDeviceIdsCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<int32_t> ids;
for (const auto& device : devices_) {
if (device.second.types.count(type) == 0)
continue;
ids.push_back(device.first);
}
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(ids)));
}
void FakeSensorService::GetAllDeviceIds(GetAllDeviceIdsCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::flat_map<int32_t, std::vector<mojom::DeviceType>> id_types;
for (const auto& device : devices_) {
id_types.emplace(device.first,
std::vector<mojom::DeviceType>(device.second.types.begin(),
device.second.types.end()));
}
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(id_types)));
}
void FakeSensorService::GetDevice(
int32_t iio_device_id,
mojo::PendingReceiver<mojom::SensorDevice> device_request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = devices_.find(iio_device_id);
if (it == devices_.end())
return;
it->second.sensor_device->Bind(std::move(device_request));
}
FakeSensorService::DeviceData::DeviceData() = default;
FakeSensorService::DeviceData::DeviceData(FakeSensorService::DeviceData&&) =
default;
FakeSensorService::DeviceData& FakeSensorService::DeviceData::operator=(
FakeSensorService::DeviceData&&) = default;
FakeSensorService::DeviceData::~DeviceData() = default;
} // namespace sensors
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_COMPONENTS_SENSORS_FAKE_SENSOR_SERVICE_H_
#define CHROMEOS_COMPONENTS_SENSORS_FAKE_SENSOR_SERVICE_H_
#include <map>
#include <set>
#include <vector>
#include "base/sequence_checker.h"
#include "chromeos/components/sensors/fake_sensor_device.h"
#include "chromeos/components/sensors/mojom/sensor.mojom.h"
namespace chromeos {
namespace sensors {
class FakeSensorService final : public mojom::SensorService {
public:
FakeSensorService();
FakeSensorService(const FakeSensorService&) = delete;
FakeSensorService& operator=(const FakeSensorService&) = delete;
~FakeSensorService() override;
bool is_bound();
void Bind(mojo::PendingReceiver<mojom::SensorService> pending_receiver);
void OnServiceDisconnect();
void SetDevice(int32_t iio_device_id,
std::set<mojom::DeviceType> types,
std::unique_ptr<FakeSensorDevice> sensor_device);
// Implementation of mojom::SensorService.
void GetDeviceIds(mojom::DeviceType type,
GetDeviceIdsCallback callback) override;
void GetAllDeviceIds(GetAllDeviceIdsCallback callback) override;
void GetDevice(
int32_t iio_device_id,
mojo::PendingReceiver<mojom::SensorDevice> device_request) override;
private:
struct DeviceData {
DeviceData();
DeviceData(DeviceData&&);
DeviceData& operator=(DeviceData&&);
~DeviceData();
std::set<mojom::DeviceType> types;
std::unique_ptr<FakeSensorDevice> sensor_device;
};
// First is the iio_device_id, second is the device's data.
std::map<int32_t, DeviceData> devices_;
mojo::Receiver<mojom::SensorService> receiver_{this};
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace sensors
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_SENSORS_FAKE_SENSOR_SERVICE_H_
......@@ -55,7 +55,7 @@ TEST_F(SensorHalDispatcherTest, ServerConnectionError) {
// Wait until the server and client get the established Mojo channel.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(fake_server->SensorServiceIsValid());
EXPECT_TRUE(fake_server->GetSensorService()->is_bound());
EXPECT_TRUE(fake_client->SensorServiceIsValid());
// Re-create a new server to simulate a server crash.
......@@ -72,7 +72,7 @@ TEST_F(SensorHalDispatcherTest, ServerConnectionError) {
// client.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(fake_server->SensorServiceIsValid());
EXPECT_TRUE(fake_server->GetSensorService()->is_bound());
EXPECT_TRUE(fake_client->SensorServiceIsValid());
}
......@@ -93,12 +93,12 @@ TEST_F(SensorHalDispatcherTest, ClientConnectionError) {
// Wait until the server and client get the established Mojo channel.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(fake_server->SensorServiceIsValid());
EXPECT_TRUE(fake_server->GetSensorService()->is_bound());
EXPECT_TRUE(fake_client->SensorServiceIsValid());
// Re-create a new client to simulate a client crash.
fake_client = std::make_unique<FakeSensorHalClient>();
fake_server->ResetSensorService();
fake_server->GetSensorService()->OnServiceDisconnect();
remote_client = fake_client->PassRemote();
SensorHalDispatcher::GetInstance()->RegisterClient(std::move(remote_client));
......@@ -107,7 +107,7 @@ TEST_F(SensorHalDispatcherTest, ClientConnectionError) {
// client.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(fake_server->SensorServiceIsValid());
EXPECT_TRUE(fake_server->GetSensorService()->is_bound());
EXPECT_TRUE(fake_client->SensorServiceIsValid());
}
......
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