blob: 17ec64fd1ef61c6bb8a9e6cf7d53a64de1b4c753 [file] [log] [blame]
Nan Zhou042b5ba2021-06-18 09:32:45 -07001// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2021 Google
3
4#include "config.hpp"
5#include "dbus_loop_mock.hpp"
6#include "host_console_mock.hpp"
7#include "stream_service.hpp"
8
9#include <sys/socket.h>
10#include <unistd.h>
11
12#include <memory>
13#include <string>
14#include <system_error>
15
16#include <gmock/gmock.h>
17#include <gtest/gtest.h>
18
19namespace
20{
21
22constexpr char socketPath[] = "\0rsyslog";
23constexpr char firstDatagram[] = "Hello world";
24constexpr char secondDatagram[] = "World hello again";
25// Shouldn't read more than maximum size of a datagram.
26constexpr int consoleReadMaxSize = 1024;
27
28using ::testing::_;
29using ::testing::DoAll;
30using ::testing::Eq;
31using ::testing::InSequence;
32using ::testing::Le;
33using ::testing::Ref;
34using ::testing::Return;
35using ::testing::SetArrayArgument;
36using ::testing::StrEq;
37using ::testing::Test;
38using ::testing::Throw;
39
40class StreamServiceTest : public Test, public StreamService
41{
42 public:
43 StreamServiceTest() :
44 StreamService(socketPath, dbusLoopMock, hostConsoleMock),
45 serverSocket(-1)
46 {}
47 ~StreamServiceTest() override
48 {
49 // Stop server
50 if (serverSocket != -1)
51 {
52 close(serverSocket);
53 }
54 }
55
56 MOCK_METHOD(void, readConsole, (), (override));
57 MOCK_METHOD(void, streamConsole, (const char* data, size_t len),
58 (override));
59 MOCK_METHOD(void, setStreamSocket, (), (override));
60
61 protected:
62 // Start a server for reading datagrams.
63 void startServer()
64 {
65 serverSocket = socket(AF_UNIX, SOCK_DGRAM, 0);
66 ASSERT_NE(serverSocket, -1);
67 sockaddr_un sa{};
68 sa.sun_family = AF_UNIX;
69 memcpy(sa.sun_path, socketPath, sizeof(socketPath) - 1);
70 sa.sun_path[sizeof(socketPath) - 1] = '\0';
Patrick Williamsb6752722023-05-10 07:50:26 -050071 const socklen_t len = sizeof(sa) - sizeof(sa.sun_path) +
72 sizeof(socketPath) - 1;
Nan Zhou042b5ba2021-06-18 09:32:45 -070073 ASSERT_NE(
74 bind(serverSocket, reinterpret_cast<const sockaddr*>(&sa), len),
75 -1);
76 }
77
78 // Set hostConsole firstly read specified data and then read nothing.
Patrick Williamsb6752722023-05-10 07:50:26 -050079 void setHostConsoleOnce(const char* data, size_t len)
Nan Zhou042b5ba2021-06-18 09:32:45 -070080 {
81 EXPECT_CALL(hostConsoleMock, read(_, Le(consoleReadMaxSize)))
82 .WillOnce(DoAll(SetArrayArgument<0>(data, data + len), Return(len)))
83 .WillOnce(Return(0));
84 }
85
86 DbusLoopMock dbusLoopMock;
87 HostConsoleMock hostConsoleMock;
88 int serverSocket;
89};
90
91TEST_F(StreamServiceTest, ReadConsoleExceptionCaught)
92{
93 InSequence sequence;
94 // Shouldn't read more than maximum size of a datagram.
95 EXPECT_CALL(hostConsoleMock, read(_, Le(1024)))
96 .WillOnce(Throw(std::system_error(std::error_code(), "Mock error")));
97 EXPECT_NO_THROW(StreamService::readConsole());
98}
99
100TEST_F(StreamServiceTest, ReadConsoleOk)
101{
102 // stream mode
103 setHostConsoleOnce(firstDatagram, strlen(firstDatagram));
104 EXPECT_CALL(*this,
105 streamConsole(StrEq(firstDatagram), Eq(strlen(firstDatagram))))
106 .WillOnce(Return());
107 EXPECT_NO_THROW(StreamService::readConsole());
108}
109
110TEST_F(StreamServiceTest, StreamConsoleOk)
111{
112 startServer();
113 EXPECT_NO_THROW(StreamService::setStreamSocket());
114 EXPECT_NO_THROW(
115 StreamService::streamConsole(firstDatagram, strlen(firstDatagram)));
116 EXPECT_NO_THROW(
117 StreamService::streamConsole(secondDatagram, strlen(secondDatagram)));
118 char buffer[consoleReadMaxSize];
119 EXPECT_EQ(read(serverSocket, buffer, consoleReadMaxSize),
120 strlen(firstDatagram));
121 buffer[strlen(firstDatagram)] = '\0';
122 EXPECT_STREQ(buffer, firstDatagram);
123 EXPECT_EQ(read(serverSocket, buffer, consoleReadMaxSize),
124 strlen(secondDatagram));
125 buffer[strlen(secondDatagram)] = '\0';
126 EXPECT_STREQ(buffer, secondDatagram);
127}
128
129TEST_F(StreamServiceTest, RunIoRegisterError)
130{
131 EXPECT_CALL(*this, setStreamSocket()).WillOnce(Return());
132 EXPECT_CALL(hostConsoleMock, connect()).WillOnce(Return());
133 EXPECT_CALL(dbusLoopMock, addSignalHandler(Eq(SIGTERM), _))
134 .WillOnce(Return());
135 EXPECT_CALL(dbusLoopMock, addIoHandler(Eq(int(hostConsoleMock)), _))
136 .WillOnce(Throw(std::runtime_error("Mock error")));
137 EXPECT_THROW(run(), std::runtime_error);
138}
139
140TEST_F(StreamServiceTest, RunSignalRegisterError)
141{
142 EXPECT_CALL(*this, setStreamSocket()).WillOnce(Return());
143 EXPECT_CALL(hostConsoleMock, connect()).WillOnce(Return());
144 EXPECT_CALL(dbusLoopMock, addSignalHandler(Eq(SIGTERM), _))
145 .WillOnce(Throw(std::runtime_error("Mock error")));
146 EXPECT_THROW(run(), std::runtime_error);
147}
148
149TEST_F(StreamServiceTest, RunOk)
150{
151 EXPECT_CALL(hostConsoleMock, connect()).WillOnce(Return());
152 EXPECT_CALL(dbusLoopMock, addIoHandler(Eq(int(hostConsoleMock)), _))
153 .WillOnce(Return());
154 EXPECT_CALL(dbusLoopMock, addSignalHandler(Eq(SIGTERM), _))
155 .WillOnce(Return());
156 EXPECT_CALL(*this, setStreamSocket()).WillOnce(Return());
157 EXPECT_CALL(dbusLoopMock, run).WillOnce(Return(0));
158 EXPECT_NO_THROW(run());
159}
160} // namespace