blob: 94678f1435eef979a514fac3277ddcde5983639a [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;
24using ::testing::Gt;
25using ::testing::InSequence;
26using ::testing::NotNull;
27using ::testing::Pointee;
28using ::testing::Return;
29using ::testing::SetArgPointee;
30using ::testing::SetErrnoAndReturn;
31using ::testing::StrEq;
32
33class NetHandleTest : public ::testing::Test
34{
35 protected:
36 NetHandleTest() : handler(&blobMock, &progMock, host, port, &sysMock)
37 {
38 sa.sin6_family = AF_INET6;
39 sa.sin6_port = htons(622);
40 sa.sin6_flowinfo = 0;
41 sa.sin6_addr = in6addr_loopback; // ::1
42 sa.sin6_scope_id = 0;
43
44 addr.ai_family = AF_INET6;
45 addr.ai_socktype = SOCK_STREAM;
46 addr.ai_addr = reinterpret_cast<struct sockaddr*>(&sa);
47 addr.ai_addrlen = sizeof(sa);
48 addr.ai_protocol = 0;
49 addr.ai_next = nullptr;
50 }
51
52 void expectOpenFile()
53 {
54 EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
55 .WillOnce(Return(inFd));
56 EXPECT_CALL(sysMock, close(inFd)).WillOnce(Return(0));
57 EXPECT_CALL(sysMock, getSize(StrEq(filePath.c_str())))
58 .WillOnce(Return(fakeFileSize));
59
60 EXPECT_CALL(progMock, start(fakeFileSize));
61 }
62
63 void expectAddrInfo()
64 {
65 EXPECT_CALL(
66 sysMock,
67 getaddrinfo(StrEq(host), StrEq(port),
68 AllOf(Field(&addrinfo::ai_flags, AI_NUMERICHOST),
Benjamin Fair2aa55342019-12-04 16:39:04 -080069 Field(&addrinfo::ai_family, AF_UNSPEC),
Benjamin Fair30d09a32019-10-11 16:57:47 -070070 Field(&addrinfo::ai_socktype, SOCK_STREAM)),
71 NotNull()))
72 .WillOnce(DoAll(SetArgPointee<3>(&addr), Return(0)));
73 EXPECT_CALL(sysMock, freeaddrinfo(&addr));
74 }
75
76 void expectConnection()
77 {
78 EXPECT_CALL(sysMock, socket(AF_INET6, SOCK_STREAM, 0))
79 .WillOnce(Return(connFd));
80 EXPECT_CALL(sysMock, close(connFd)).WillOnce(Return(0));
81 EXPECT_CALL(sysMock,
82 connect(connFd, reinterpret_cast<struct sockaddr*>(&sa),
83 sizeof(sa)))
84 .WillOnce(Return(0));
85 }
86
87 internal::InternalSysMock sysMock;
88 ipmiblob::BlobInterfaceMock blobMock;
89 ProgressMock progMock;
90
91 const std::string host = "::1"s;
92 const std::string port = "622"s;
93
94 struct sockaddr_in6 sa;
95 struct addrinfo addr;
96
97 static constexpr std::uint16_t session = 0xbeef;
98 const std::string filePath = "/asdf"s;
99 static constexpr int inFd = 5;
100 static constexpr int connFd = 7;
101 static constexpr size_t fakeFileSize = 128;
102 static constexpr size_t chunkSize = 16;
103
104 NetDataHandler handler;
105};
106
107TEST_F(NetHandleTest, openFileFail)
108{
109 EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
110 .WillOnce(SetErrnoAndReturn(EACCES, -1));
111
112 EXPECT_FALSE(handler.sendContents(filePath, session));
113}
114
115TEST_F(NetHandleTest, getSizeFail)
116{
117 EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
118 .WillOnce(Return(inFd));
119 EXPECT_CALL(sysMock, close(inFd)).WillOnce(Return(0));
120 EXPECT_CALL(sysMock, getSize(StrEq(filePath.c_str()))).WillOnce(Return(0));
121
122 EXPECT_FALSE(handler.sendContents(filePath, session));
123}
124
125TEST_F(NetHandleTest, getaddrinfoFail)
126{
127 expectOpenFile();
128
129 EXPECT_CALL(sysMock,
130 getaddrinfo(StrEq(host), StrEq(port),
131 AllOf(Field(&addrinfo::ai_flags, AI_NUMERICHOST),
Benjamin Fair2aa55342019-12-04 16:39:04 -0800132 Field(&addrinfo::ai_family, AF_UNSPEC),
Benjamin Fair30d09a32019-10-11 16:57:47 -0700133 Field(&addrinfo::ai_socktype, SOCK_STREAM)),
134 NotNull()))
135 .WillOnce(Return(EAI_ADDRFAMILY));
136
137 EXPECT_FALSE(handler.sendContents(filePath, session));
138}
139
140TEST_F(NetHandleTest, connectFail)
141{
142 expectOpenFile();
143 expectAddrInfo();
144
145 EXPECT_CALL(sysMock, socket(AF_INET6, SOCK_STREAM, 0))
146 .WillOnce(Return(connFd));
147 EXPECT_CALL(sysMock, close(connFd)).WillOnce(Return(0));
148 EXPECT_CALL(
149 sysMock,
150 connect(connFd, reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)))
151 .WillOnce(SetErrnoAndReturn(ECONNREFUSED, -1));
152
153 EXPECT_FALSE(handler.sendContents(filePath, session));
154}
155
156TEST_F(NetHandleTest, sendfileFail)
157{
158 expectOpenFile();
159 expectAddrInfo();
160 expectConnection();
161
162 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(0), _))
163 .WillOnce(SetErrnoAndReturn(ETIMEDOUT, -1));
164
165 EXPECT_FALSE(handler.sendContents(filePath, session));
166}
167
168TEST_F(NetHandleTest, successOneChunk)
169{
170 expectOpenFile();
171 expectAddrInfo();
172 expectConnection();
173
174 {
175 InSequence seq;
176
177 EXPECT_CALL(sysMock,
178 sendfile(connFd, inFd, Pointee(0), Gt(fakeFileSize)))
179 .WillOnce(
180 DoAll(SetArgPointee<2>(fakeFileSize), Return(fakeFileSize)));
181 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(fakeFileSize),
182 Gt(fakeFileSize)))
183 .WillOnce(Return(0));
184 }
185
186 struct ipmi_flash::ExtChunkHdr chunk;
187 chunk.length = fakeFileSize;
188 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
189 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
190 EXPECT_CALL(blobMock, writeBytes(session, 0, ContainerEq(chunkBytes)));
191
192 EXPECT_CALL(progMock, updateProgress(fakeFileSize));
193
194 EXPECT_TRUE(handler.sendContents(filePath, session));
195}
196
197TEST_F(NetHandleTest, successMultiChunk)
198{
199 expectOpenFile();
200 expectAddrInfo();
201 expectConnection();
202
203 struct ipmi_flash::ExtChunkHdr chunk;
204 chunk.length = chunkSize;
205 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
206 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
207
208 {
209 InSequence seq;
210
211 for (std::uint32_t offset = 0; offset < fakeFileSize;
212 offset += chunkSize)
213 {
214 EXPECT_CALL(sysMock,
215 sendfile(connFd, inFd, Pointee(offset), Gt(chunkSize)))
216 .WillOnce(DoAll(SetArgPointee<2>(offset + chunkSize),
217 Return(chunkSize)));
218
219 EXPECT_CALL(blobMock,
220 writeBytes(session, offset, ContainerEq(chunkBytes)));
221 EXPECT_CALL(progMock, updateProgress(chunkSize));
222 }
223 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(fakeFileSize),
224 Gt(chunkSize)))
225 .WillOnce(Return(0));
226 }
227
228 EXPECT_TRUE(handler.sendContents(filePath, session));
229}
230
231} // namespace
232} // namespace host_tool