blob: 3e9828400b2ad387b6ea147dcdf01a36da3ac503 [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/diagnosticsd/bind_utils.h"
#include "diagnostics/diagnosticsd/diagnosticsd_ec_event_service.h"
#include "diagnostics/diagnosticsd/ec_constants.h"
using testing::_;
using testing::Invoke;
using testing::StrictMock;
namespace diagnostics {
namespace {
class MockDiagnosticsdEcEventServiceDelegate
: public DiagnosticsdEcEventService::Delegate {
public:
MOCK_METHOD1(SendGrpcEcEventToDiagnosticsProcessor,
void(const DiagnosticsdEcEventService::EcEvent& ec_event));
};
class DiagnosticsdEcEventServiceTest : public testing::Test {
protected:
DiagnosticsdEcEventServiceTest() : 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 CreateSysfsFile() {
base::FilePath file_path = sysfs_file_path();
ASSERT_TRUE(base::CreateDirectory(file_path.DirName()));
ASSERT_EQ(mkfifo(file_path.value().c_str(), 0600), 0);
}
base::FilePath sysfs_file_path() {
return temp_dir_.GetPath().Append(kEcEventSysfsPath);
}
// 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(sysfs_file_path().value().c_str(), O_WRONLY));
ASSERT_NE(fifo_write_end_.get(), -1);
}
void WriteEventToSysfsFile(
const DiagnosticsdEcEventService::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_, SendGrpcEcEventToDiagnosticsProcessor(ec_event))
.WillOnce(Invoke(
[callback](const DiagnosticsdEcEventService::EcEvent& ec_event) {
callback.Run();
}));
}
MockDiagnosticsdEcEventServiceDelegate* delegate() { return &delegate_; }
DiagnosticsdEcEventService* service() { return &service_; }
private:
base::MessageLoop message_loop_;
StrictMock<MockDiagnosticsdEcEventServiceDelegate> delegate_;
DiagnosticsdEcEventService service_;
base::ScopedTempDir temp_dir_;
base::ScopedFD fifo_write_end_;
};
} // namespace
TEST_F(DiagnosticsdEcEventServiceTest, Start) {
CreateSysfsFile();
ASSERT_TRUE(service()->Start());
}
TEST_F(DiagnosticsdEcEventServiceTest, StartFailure) {
ASSERT_FALSE(service()->Start());
}
TEST_F(DiagnosticsdEcEventServiceTest, ReadEvent) {
CreateSysfsFile();
ASSERT_TRUE(service()->Start());
InitFifoWriteEnd();
base::RunLoop run_loop;
const uint16_t data[6] = {0xaaaa, 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff};
WriteEventToSysfsFile(
DiagnosticsdEcEventService::EcEvent(0x8888, 0x9999, data),
run_loop.QuitClosure());
run_loop.Run();
}
TEST_F(DiagnosticsdEcEventServiceTest, ReadManyEvent) {
CreateSysfsFile();
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};
WriteEventToSysfsFile(
DiagnosticsdEcEventService::EcEvent(0x8888, 0x9999, data1), callback);
const uint16_t data2[6] = {0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555};
WriteEventToSysfsFile(
DiagnosticsdEcEventService::EcEvent(0x6666, 0x7777, data2), callback);
run_loop.Run();
}
} // namespace diagnostics