blob: 63b955f54864bb6337aec212a4af321ed357c2b5 [file]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "runtime_probe/utils/pipe_utils.h"
#include <algorithm>
#include <string>
#include <vector>
#include <base/json/json_reader.h>
#include <gtest/gtest.h>
#include "runtime_probe/utils/function_test_utils.h"
namespace runtime_probe {
namespace {
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Return;
constexpr int kDefaultTimeout = 5;
class PipeUtilsTest : public BaseFunctionTest {};
TEST_F(PipeUtilsTest, ReadNonblockingPipeToString_Success) {
const int kFd1 = 3;
const int kFd2 = 5;
std::vector<int> fds = {kFd1, kFd2};
std::vector<std::string> out;
auto syscaller = mock_context()->mock_syscaller();
EXPECT_CALL(*syscaller, Select)
.WillOnce([&kFd1, &kFd2](int nfds, fd_set* read_fds, auto, auto, auto) {
EXPECT_EQ(nfds, std::max(kFd1, kFd2) + 1);
EXPECT_TRUE(FD_ISSET(kFd1, read_fds));
EXPECT_TRUE(FD_ISSET(kFd2, read_fds));
// Set The file descriptor |kFd1| not ready.
FD_CLR(kFd1, read_fds);
return 1;
})
.WillOnce([&kFd1, &kFd2](int nfds, fd_set* read_fds, auto, auto, auto) {
EXPECT_EQ(nfds, std::max(kFd1, kFd2) + 1);
EXPECT_TRUE(FD_ISSET(kFd1, read_fds));
EXPECT_TRUE(FD_ISSET(kFd2, read_fds));
// Both the file descriptors are ready.
return 2;
})
.WillOnce([&kFd1, &kFd2](int nfds, fd_set* read_fds, auto, auto, auto) {
EXPECT_EQ(nfds, std::max(kFd1, kFd2) + 1);
EXPECT_TRUE(FD_ISSET(kFd1, read_fds));
EXPECT_TRUE(FD_ISSET(kFd2, read_fds));
// Both the file descriptors are ready.
return 2;
})
.WillOnce([](int nfds, fd_set* read_fds, auto, auto, auto) {
// |kFd2| was not set because it has already been read completely.
EXPECT_EQ(nfds, kFd1 + 1);
EXPECT_TRUE(FD_ISSET(kFd1, read_fds));
EXPECT_FALSE(FD_ISSET(kFd2, read_fds));
return 1;
});
// Read from file descriptor |kFd1|.
EXPECT_CALL(*syscaller, Read(kFd1, _, _))
.WillOnce([](int fd, void* buffer, auto) {
char res[] = {'1', '2', '3', '4'};
std::copy(res, res + sizeof(res), reinterpret_cast<char*>(buffer));
return sizeof(res);
})
.WillOnce([](int fd, void* buffer, auto) {
char res[] = {'5', '6', '7', '8'};
std::copy(res, res + sizeof(res), reinterpret_cast<char*>(buffer));
return sizeof(res);
})
.WillOnce(Return(0));
// Read from file descriptor |kFd2|.
EXPECT_CALL(*syscaller, Read(kFd2, _, _))
.WillOnce([](int fd, void* buffer, auto) {
char res[] = {'a', 'b', 'c'};
std::copy(res, res + sizeof(res), reinterpret_cast<char*>(buffer));
return sizeof(res);
})
.WillOnce([](int fd, void* buffer, auto) {
char res[] = {'d', 'e', 'f'};
std::copy(res, res + sizeof(res), reinterpret_cast<char*>(buffer));
return sizeof(res);
})
.WillOnce(Return(0));
EXPECT_TRUE(ReadNonblockingPipeToString(fds, &out, kDefaultTimeout));
EXPECT_THAT(out, ElementsAre("12345678", "abcdef"));
}
TEST_F(PipeUtilsTest, ReadNonblockingPipeToString_ReadFailed) {
const int kFd1 = 3;
const int kFd2 = 5;
std::vector<int> fds = {kFd1, kFd2};
std::vector<std::string> out;
auto syscaller = mock_context()->mock_syscaller();
EXPECT_CALL(*syscaller, Select).WillOnce(Return(2));
// Return -1 on read() failure.
EXPECT_CALL(*syscaller, Read).WillOnce(Return(-1));
EXPECT_FALSE(ReadNonblockingPipeToString(fds, &out, kDefaultTimeout));
EXPECT_THAT(out, ElementsAre("", ""));
}
TEST_F(PipeUtilsTest, ReadNonblockingPipeToString_SelectTimeOut) {
const int kFd1 = 3;
const int kFd2 = 5;
std::vector<int> fds = {kFd1, kFd2};
std::vector<std::string> out;
auto syscaller = mock_context()->mock_syscaller();
// Return 0 on select() timeout.
EXPECT_CALL(*syscaller, Select).WillOnce(Return(0));
EXPECT_FALSE(ReadNonblockingPipeToString(fds, &out, kDefaultTimeout));
EXPECT_THAT(out, ElementsAre("", ""));
}
TEST_F(PipeUtilsTest, ReadNonblockingPipeToString_SelectFailed) {
const int kFd1 = 3;
const int kFd2 = 5;
std::vector<int> fds = {kFd1, kFd2};
std::vector<std::string> out;
auto syscaller = mock_context()->mock_syscaller();
// Return -1 on select() failure.
EXPECT_CALL(*syscaller, Select).WillOnce(Return(-1));
EXPECT_FALSE(ReadNonblockingPipeToString(fds, &out, kDefaultTimeout));
EXPECT_THAT(out, ElementsAre("", ""));
}
} // namespace
} // namespace runtime_probe