blob: b291e1c290ef9a8d86e987beaa08e4f775bc7cdd [file] [log] [blame]
Benjamin Fair30d09a32019-10-11 16:57:47 -07001#include "data.hpp"
2#include "internal_sys_mock.hpp"
3#include "net.hpp"
4#include "progress_mock.hpp"
5
Benjamin Fair30d09a32019-10-11 16:57:47 -07006#include <ipmiblob/test/blob_interface_mock.hpp>
7
Patrick Venture9b37b092020-05-28 20:58:57 -07008#include <cstring>
9
Benjamin Fair30d09a32019-10-11 16:57:47 -070010#include <gtest/gtest.h>
11
12namespace host_tool
13{
14namespace
15{
16
17using namespace std::literals;
18
19using ::testing::_;
20using ::testing::AllOf;
21using ::testing::ContainerEq;
Rui Zhang382d2a02020-03-25 11:12:30 -070022using ::testing::DoAll;
Benjamin Fair30d09a32019-10-11 16:57:47 -070023using ::testing::Field;
William A. Kennington III9bb21e32022-04-08 14:28:50 -070024using ::testing::Ge;
Benjamin Fair30d09a32019-10-11 16:57:47 -070025using ::testing::Gt;
26using ::testing::InSequence;
27using ::testing::NotNull;
28using ::testing::Pointee;
29using ::testing::Return;
30using ::testing::SetArgPointee;
31using ::testing::SetErrnoAndReturn;
32using ::testing::StrEq;
33
34class NetHandleTest : public ::testing::Test
35{
36 protected:
37 NetHandleTest() : handler(&blobMock, &progMock, host, port, &sysMock)
38 {
39 sa.sin6_family = AF_INET6;
40 sa.sin6_port = htons(622);
41 sa.sin6_flowinfo = 0;
42 sa.sin6_addr = in6addr_loopback; // ::1
43 sa.sin6_scope_id = 0;
44
45 addr.ai_family = AF_INET6;
46 addr.ai_socktype = SOCK_STREAM;
47 addr.ai_addr = reinterpret_cast<struct sockaddr*>(&sa);
48 addr.ai_addrlen = sizeof(sa);
49 addr.ai_protocol = 0;
50 addr.ai_next = nullptr;
51 }
52
53 void expectOpenFile()
54 {
55 EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
56 .WillOnce(Return(inFd));
57 EXPECT_CALL(sysMock, close(inFd)).WillOnce(Return(0));
58 EXPECT_CALL(sysMock, getSize(StrEq(filePath.c_str())))
59 .WillOnce(Return(fakeFileSize));
Benjamin Fair30d09a32019-10-11 16:57:47 -070060 }
61
62 void expectAddrInfo()
63 {
64 EXPECT_CALL(
65 sysMock,
66 getaddrinfo(StrEq(host), StrEq(port),
67 AllOf(Field(&addrinfo::ai_flags, AI_NUMERICHOST),
Benjamin Fair2aa55342019-12-04 16:39:04 -080068 Field(&addrinfo::ai_family, AF_UNSPEC),
Benjamin Fair30d09a32019-10-11 16:57:47 -070069 Field(&addrinfo::ai_socktype, SOCK_STREAM)),
70 NotNull()))
71 .WillOnce(DoAll(SetArgPointee<3>(&addr), Return(0)));
72 EXPECT_CALL(sysMock, freeaddrinfo(&addr));
73 }
74
75 void expectConnection()
76 {
77 EXPECT_CALL(sysMock, socket(AF_INET6, SOCK_STREAM, 0))
78 .WillOnce(Return(connFd));
79 EXPECT_CALL(sysMock, close(connFd)).WillOnce(Return(0));
80 EXPECT_CALL(sysMock,
81 connect(connFd, reinterpret_cast<struct sockaddr*>(&sa),
82 sizeof(sa)))
83 .WillOnce(Return(0));
84 }
85
86 internal::InternalSysMock sysMock;
87 ipmiblob::BlobInterfaceMock blobMock;
88 ProgressMock progMock;
89
90 const std::string host = "::1"s;
91 const std::string port = "622"s;
92
93 struct sockaddr_in6 sa;
94 struct addrinfo addr;
95
96 static constexpr std::uint16_t session = 0xbeef;
97 const std::string filePath = "/asdf"s;
98 static constexpr int inFd = 5;
99 static constexpr int connFd = 7;
100 static constexpr size_t fakeFileSize = 128;
101 static constexpr size_t chunkSize = 16;
102
103 NetDataHandler handler;
104};
105
106TEST_F(NetHandleTest, openFileFail)
107{
108 EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
109 .WillOnce(SetErrnoAndReturn(EACCES, -1));
110
111 EXPECT_FALSE(handler.sendContents(filePath, session));
112}
113
Benjamin Fair30d09a32019-10-11 16:57:47 -0700114TEST_F(NetHandleTest, getaddrinfoFail)
115{
116 expectOpenFile();
117
118 EXPECT_CALL(sysMock,
119 getaddrinfo(StrEq(host), StrEq(port),
120 AllOf(Field(&addrinfo::ai_flags, AI_NUMERICHOST),
Benjamin Fair2aa55342019-12-04 16:39:04 -0800121 Field(&addrinfo::ai_family, AF_UNSPEC),
Benjamin Fair30d09a32019-10-11 16:57:47 -0700122 Field(&addrinfo::ai_socktype, SOCK_STREAM)),
123 NotNull()))
124 .WillOnce(Return(EAI_ADDRFAMILY));
125
126 EXPECT_FALSE(handler.sendContents(filePath, session));
127}
128
129TEST_F(NetHandleTest, connectFail)
130{
131 expectOpenFile();
132 expectAddrInfo();
133
134 EXPECT_CALL(sysMock, socket(AF_INET6, SOCK_STREAM, 0))
135 .WillOnce(Return(connFd));
136 EXPECT_CALL(sysMock, close(connFd)).WillOnce(Return(0));
137 EXPECT_CALL(
138 sysMock,
139 connect(connFd, reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)))
140 .WillOnce(SetErrnoAndReturn(ECONNREFUSED, -1));
141
142 EXPECT_FALSE(handler.sendContents(filePath, session));
143}
144
145TEST_F(NetHandleTest, sendfileFail)
146{
147 expectOpenFile();
148 expectAddrInfo();
149 expectConnection();
150
151 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(0), _))
152 .WillOnce(SetErrnoAndReturn(ETIMEDOUT, -1));
153
154 EXPECT_FALSE(handler.sendContents(filePath, session));
155}
156
157TEST_F(NetHandleTest, successOneChunk)
158{
159 expectOpenFile();
160 expectAddrInfo();
161 expectConnection();
162
163 {
164 InSequence seq;
165
166 EXPECT_CALL(sysMock,
167 sendfile(connFd, inFd, Pointee(0), Gt(fakeFileSize)))
168 .WillOnce(
169 DoAll(SetArgPointee<2>(fakeFileSize), Return(fakeFileSize)));
170 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(fakeFileSize),
171 Gt(fakeFileSize)))
172 .WillOnce(Return(0));
173 }
174
175 struct ipmi_flash::ExtChunkHdr chunk;
176 chunk.length = fakeFileSize;
177 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
178 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
179 EXPECT_CALL(blobMock, writeBytes(session, 0, ContainerEq(chunkBytes)));
180
181 EXPECT_CALL(progMock, updateProgress(fakeFileSize));
182
183 EXPECT_TRUE(handler.sendContents(filePath, session));
184}
185
186TEST_F(NetHandleTest, successMultiChunk)
187{
188 expectOpenFile();
189 expectAddrInfo();
190 expectConnection();
191
192 struct ipmi_flash::ExtChunkHdr chunk;
193 chunk.length = chunkSize;
194 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
195 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
196
197 {
198 InSequence seq;
199
200 for (std::uint32_t offset = 0; offset < fakeFileSize;
201 offset += chunkSize)
202 {
203 EXPECT_CALL(sysMock,
204 sendfile(connFd, inFd, Pointee(offset), Gt(chunkSize)))
205 .WillOnce(DoAll(SetArgPointee<2>(offset + chunkSize),
206 Return(chunkSize)));
207
208 EXPECT_CALL(blobMock,
209 writeBytes(session, offset, ContainerEq(chunkBytes)));
210 EXPECT_CALL(progMock, updateProgress(chunkSize));
211 }
212 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(fakeFileSize),
213 Gt(chunkSize)))
214 .WillOnce(Return(0));
215 }
216
217 EXPECT_TRUE(handler.sendContents(filePath, session));
218}
219
William A. Kennington III9bb21e32022-04-08 14:28:50 -0700220TEST_F(NetHandleTest, successFallback)
221{
222 expectOpenFile();
223 expectAddrInfo();
224 expectConnection();
225
226 struct ipmi_flash::ExtChunkHdr chunk;
227 chunk.length = chunkSize;
228 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
229 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
230
231 {
232 InSequence seq;
233 EXPECT_CALL(sysMock, sendfile(connFd, inFd, _, _))
234 .WillOnce([](int, int, off_t*, size_t) {
235 errno = EINVAL;
236 return -1;
237 });
238
239 std::vector<uint8_t> chunk(chunkSize);
240 for (std::uint32_t offset = 0; offset < fakeFileSize;
241 offset += chunkSize)
242 {
243 for (size_t i = 0; i < chunkSize; ++i)
244 {
245 chunk[i] = i + offset;
246 }
247 EXPECT_CALL(sysMock, read(inFd, _, Ge(chunkSize)))
248 .WillOnce([chunk](int, void* buf, size_t) {
249 memcpy(buf, chunk.data(), chunkSize);
250 return chunkSize;
251 });
252 EXPECT_CALL(sysMock, send(connFd, _, chunkSize, 0))
253 .WillOnce([chunk](int, const void* data, size_t len, int) {
254 std::vector<uint8_t> dcopy(len);
255 memcpy(dcopy.data(), data, len);
256 EXPECT_THAT(dcopy, ContainerEq(chunk));
257 return chunkSize;
258 });
259 EXPECT_CALL(blobMock,
260 writeBytes(session, offset, ContainerEq(chunkBytes)));
261 EXPECT_CALL(progMock, updateProgress(chunkSize));
262 }
263 EXPECT_CALL(sysMock, read(inFd, _, Ge(chunkSize))).WillOnce(Return(0));
264 EXPECT_CALL(sysMock, send(connFd, _, 0, 0)).WillOnce(Return(0));
265 }
266
267 EXPECT_TRUE(handler.sendContents(filePath, session));
268}
269
Benjamin Fair30d09a32019-10-11 16:57:47 -0700270} // namespace
271} // namespace host_tool