blob: cb088f6020c62ced992ce88bd1e04b6d06408a6c [file] [log] [blame]
// Copyright 2018 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 <fcntl.h>
#include <poll.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstdint>
#include <base/bind.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/files/scoped_temp_dir.h>
#include <base/message_loop/message_loop.h>
#include <base/run_loop.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "diagnostics/wilco_dtc_supportd/bind_utils.h"
#include "diagnostics/wilco_dtc_supportd/ec_constants.h"
#include "diagnostics/wilco_dtc_supportd/wilco_dtc_supportd_ec_event_service.h"
using testing::_;
using testing::Invoke;
using testing::StrictMock;
namespace diagnostics {
namespace {
class MockWilcoDtcSupportdEcEventServiceDelegate
: public WilcoDtcSupportdEcEventService::Delegate {
public:
MOCK_METHOD1(SendGrpcEcEventToWilcoDtc,
void(const WilcoDtcSupportdEcEventService::EcEvent& ec_event));
};
class WilcoDtcSupportdEcEventServiceTest : public testing::Test {
protected:
WilcoDtcSupportdEcEventServiceTest() : service_(&delegate_) {}
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
service()->set_root_dir_for_testing(temp_dir_.GetPath());
service()->set_event_fd_events_for_testing(POLLIN);
}
void TearDown() override {
base::RunLoop run_loop;
service_.Shutdown(run_loop.QuitClosure());
run_loop.Run();
}
void CreateEcEventFile() {
base::FilePath file_path = ec_event_file_path();
ASSERT_TRUE(base::CreateDirectory(file_path.DirName()));
ASSERT_EQ(mkfifo(file_path.value().c_str(), 0600), 0);
}
base::FilePath ec_event_file_path() {
return temp_dir_.GetPath().Append(kEcEventFilePath);
}
// Must be open only after |service_->Start()| call. Otherwise, it will
// block thread.
void InitFifoWriteEnd() {
ASSERT_EQ(fifo_write_end_.get(), -1);
fifo_write_end_.reset(open(ec_event_file_path().value().c_str(), O_WRONLY));
ASSERT_NE(fifo_write_end_.get(), -1);
}
void WriteEventToEcEventFile(
const WilcoDtcSupportdEcEventService::EcEvent& ec_event,
const base::RepeatingClosure& callback) {
ASSERT_EQ(write(fifo_write_end_.get(), &ec_event, sizeof(ec_event)),
sizeof(ec_event));
EXPECT_CALL(delegate_, SendGrpcEcEventToWilcoDtc(ec_event))
.WillOnce(Invoke(
[callback](
const WilcoDtcSupportdEcEventService::EcEvent& ec_event) {
callback.Run();
}));
}
MockWilcoDtcSupportdEcEventServiceDelegate* delegate() { return &delegate_; }
WilcoDtcSupportdEcEventService* service() { return &service_; }
private:
base::MessageLoop message_loop_;
StrictMock<MockWilcoDtcSupportdEcEventServiceDelegate> delegate_;
WilcoDtcSupportdEcEventService service_;
base::ScopedTempDir temp_dir_;
base::ScopedFD fifo_write_end_;
};
} // namespace
TEST_F(WilcoDtcSupportdEcEventServiceTest, Start) {
CreateEcEventFile();
ASSERT_TRUE(service()->Start());
}
TEST_F(WilcoDtcSupportdEcEventServiceTest, StartFailure) {
ASSERT_FALSE(service()->Start());
}
TEST_F(WilcoDtcSupportdEcEventServiceTest, ReadEvent) {
CreateEcEventFile();
ASSERT_TRUE(service()->Start());
InitFifoWriteEnd();
base::RunLoop run_loop;
const uint16_t data[6] = {0xaaaa, 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff};
WriteEventToEcEventFile(
WilcoDtcSupportdEcEventService::EcEvent(0x8888, 0x9999, data),
run_loop.QuitClosure());
run_loop.Run();
}
TEST_F(WilcoDtcSupportdEcEventServiceTest, ReadManyEvent) {
CreateEcEventFile();
ASSERT_TRUE(service()->Start());
InitFifoWriteEnd();
base::RunLoop run_loop;
base::RepeatingClosure callback = BarrierClosure(
2 /* num_closures */, run_loop.QuitClosure() /* done closure */);
const uint16_t data1[6] = {0xaaaa, 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff};
WriteEventToEcEventFile(
WilcoDtcSupportdEcEventService::EcEvent(0x8888, 0x9999, data1), callback);
const uint16_t data2[6] = {0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555};
WriteEventToEcEventFile(
WilcoDtcSupportdEcEventService::EcEvent(0x6666, 0x7777, data2), callback);
run_loop.Run();
}
} // namespace diagnostics