blob: 900fb103c927965c03896741d738cf121e68f454 [file] [log] [blame]
// Copyright 2022 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 <gtest/gtest.h>
#include <memory>
#include <utility>
#include <vector>
#include <base/notreached.h>
#include <base/rand_util.h>
#include <base/test/task_environment.h>
#include <libmems/test_fakes.h>
#include <mojo/public/cpp/bindings/receiver_set.h>
#include "iioservice/daemon/events_handler.h"
#include "iioservice/daemon/test_fakes.h"
namespace iioservice {
namespace {
constexpr int kNumFailures = 10;
// An observer that does nothing to events or errors. Instead, it simply waits
// for the mojo disconnection and calls |quit_closure|.
class FakeObserver : cros::mojom::SensorDeviceEventsObserver {
public:
explicit FakeObserver(base::RepeatingClosure quit_closure)
: quit_closure_(std::move(quit_closure)) {}
mojo::PendingRemote<cros::mojom::SensorDeviceEventsObserver> GetRemote() {
CHECK(!receiver_.is_bound());
auto pending_remote = receiver_.BindNewPipeAndPassRemote();
receiver_.set_disconnect_handler(base::BindOnce(
&FakeObserver::OnObserverDisconnect, base::Unretained(this)));
return pending_remote;
}
// cros::mojom::SensorDeviceEventsObserver overrides:
void OnEventUpdated(cros::mojom::IioEventPtr event) override {}
void OnErrorOccurred(cros::mojom::ObserverErrorType type) override {}
private:
void OnObserverDisconnect() {
receiver_.reset();
quit_closure_.Run();
}
base::RepeatingClosure quit_closure_;
mojo::Receiver<cros::mojom::SensorDeviceEventsObserver> receiver_{this};
};
class EventsHandlerTest : public ::testing::Test,
public cros::mojom::SensorDeviceEventsObserver {
public:
mojo::PendingRemote<cros::mojom::SensorDeviceEventsObserver> GetRemote() {
mojo::PendingRemote<cros::mojom::SensorDeviceEventsObserver> remote;
receiver_set_.Add(this, remote.InitWithNewPipeAndPassReceiver());
return remote;
}
// cros::mojom::SensorDeviceEventsObserver overrides:
void OnEventUpdated(cros::mojom::IioEventPtr event) override { NOTREACHED(); }
void OnErrorOccurred(cros::mojom::ObserverErrorType type) override {
NOTREACHED();
}
protected:
void SetUp() override {
device_ =
std::make_unique<libmems::fakes::FakeIioDevice>(nullptr, "sx9310", 0);
for (int i = 0; i < 4; ++i) {
device_->AddEvent(std::make_unique<libmems::fakes::FakeIioEvent>(
iio_chan_type::IIO_PROXIMITY, iio_event_type::IIO_EV_TYPE_THRESH,
iio_event_direction::IIO_EV_DIR_EITHER, i));
}
handler_ = EventsHandler::Create(
task_environment_.GetMainThreadTaskRunner(),
task_environment_.GetMainThreadTaskRunner(), device_.get());
EXPECT_TRUE(handler_);
}
void TearDown() override {
handler_.reset();
observers_.clear();
base::RunLoop().RunUntilIdle();
// ClientData should be valid until |handler_| is destructed.
clients_data_.clear();
}
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME,
base::test::TaskEnvironment::MainThreadType::IO};
std::unique_ptr<libmems::fakes::FakeIioDevice> device_;
EventsHandler::ScopedEventsHandler handler_ = {
nullptr, EventsHandler::EventsHandlerDeleter};
std::unique_ptr<DeviceData> device_data_;
std::vector<ClientData> clients_data_;
std::vector<std::unique_ptr<fakes::FakeEventsObserver>> observers_;
mojo::ReceiverSet<cros::mojom::SensorDeviceEventsObserver> receiver_set_;
};
TEST_F(EventsHandlerTest, AddClientAndRemoveClient) {
// No events in this test
device_->SetPauseCallbackAtKthEvents(0, base::BindOnce([]() {}));
device_data_ = std::make_unique<DeviceData>(
device_.get(),
std::set<cros::mojom::DeviceType>{cros::mojom::DeviceType::PROXIMITY});
// ClientData should be valid until |handler_| is destructed.
clients_data_.emplace_back(ClientData(0, device_data_.get()));
ClientData& client_data = clients_data_[0];
client_data.enabled_event_indices.emplace(3); // timestamp
handler_->AddClient(&client_data, GetRemote());
{
base::RunLoop run_loop;
FakeObserver observer(run_loop.QuitClosure());
handler_->AddClient(&client_data, observer.GetRemote());
// Wait until |Observer| is disconnected.
run_loop.Run();
}
{
base::RunLoop run_loop;
handler_->RemoveClient(&client_data, run_loop.QuitClosure());
run_loop.Run();
}
{ // RemoveClient can be called multiple times.
base::RunLoop run_loop;
handler_->RemoveClient(&client_data, run_loop.QuitClosure());
run_loop.Run();
}
}
// Add clients with only the event with channel 3 enabled, enable all other
// channels, and disable all channels except for event with channel 0. Enabled
// channels are checked after each modification.
TEST_F(EventsHandlerTest, UpdateEventsEnabled) {
// No events in this test
device_->SetPauseCallbackAtKthEvents(0, base::BindOnce([]() {}));
device_data_ = std::make_unique<DeviceData>(
device_.get(),
std::set<cros::mojom::DeviceType>{cros::mojom::DeviceType::PROXIMITY});
clients_data_.emplace_back(ClientData(0, device_data_.get()));
ClientData& client_data = clients_data_[0];
// At least one channel enabled
client_data.enabled_event_indices.emplace(3);
handler_->AddClient(&client_data, GetRemote());
handler_->UpdateEventsEnabled(
&client_data, std::vector<int32_t>{1, 0, 2}, true,
base::BindOnce([](const std::vector<int32_t>& failed_indices) {
EXPECT_TRUE(failed_indices.empty());
}));
handler_->GetEventsEnabled(
&client_data, std::vector<int32_t>{1, 0, 2, 3},
base::BindOnce([](const std::vector<bool>& enabled) {
EXPECT_EQ(enabled.size(), 4);
EXPECT_TRUE(enabled[0] && enabled[1] && enabled[2] && enabled[3]);
}));
handler_->UpdateEventsEnabled(
&client_data, std::vector<int32_t>{2, 1, 3}, false,
base::BindOnce(
[](ClientData* client_data, int32_t chn_index,
const std::vector<int32_t>& failed_indices) {
EXPECT_EQ(client_data->enabled_event_indices.size(), 1);
EXPECT_EQ(*client_data->enabled_event_indices.begin(), chn_index);
EXPECT_TRUE(failed_indices.empty());
},
&client_data, 0));
handler_->RemoveClient(&client_data, base::DoNothing());
}
// Add all clients into the event handler, and read all events. All events are
// checked when received by observers.
TEST_F(EventsHandlerTest, ReadEventsWithEnabledFakeIioEvents) {
// Set the pause in the beginning to prevent reading events before all
// clients added.
device_->SetPauseCallbackAtKthEvents(0, base::BindOnce([]() {}));
device_data_ = std::make_unique<DeviceData>(
device_.get(),
std::set<cros::mojom::DeviceType>{cros::mojom::DeviceType::PROXIMITY});
std::multiset<std::pair<int, cros::mojom::ObserverErrorType>> failures;
for (int i = 0; i < kNumFailures; ++i) {
int k = base::RandInt(0, libmems::fakes::kEventNumber - 1);
device_->AddFailedReadAtKthEvent(k);
failures.insert(
std::make_pair(k, cros::mojom::ObserverErrorType::READ_FAILED));
}
std::vector<std::set<int32_t>> clients = {
{0, 1},
{0},
};
clients_data_.reserve(clients.size());
for (size_t i = 0; i < clients.size(); ++i) {
clients_data_.emplace_back(ClientData(i, device_data_.get()));
ClientData& client_data = clients_data_[i];
client_data.enabled_event_indices = clients[i];
// The fake observer needs |max_freq| and |max_freq2| to calculate the
// correct values of events
auto fake_observer = std::make_unique<fakes::FakeEventsObserver>(
device_.get(), failures, clients[i]);
handler_->AddClient(&client_data, fake_observer->GetRemote());
observers_.emplace_back(std::move(fake_observer));
}
// TODO(chenghaoyang): pause and enable other FakeIioEvents.
device_->ResumeReadingEvents();
// Wait until all observers receive all events.
base::RunLoop().RunUntilIdle();
for (const auto& observer : observers_)
EXPECT_TRUE(observer->FinishedObserving());
// Remove clients
for (auto& client_data : clients_data_)
handler_->RemoveClient(&client_data, base::DoNothing());
}
} // namespace
} // namespace iioservice