blob: f741edb5d00e8269669fcca3a598881c1f0c9763 [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));
Benjamin Fair30d09a32019-10-11 16:57:47 -070059 }
60
61 void expectAddrInfo()
62 {
63 EXPECT_CALL(
64 sysMock,
65 getaddrinfo(StrEq(host), StrEq(port),
66 AllOf(Field(&addrinfo::ai_flags, AI_NUMERICHOST),
Benjamin Fair2aa55342019-12-04 16:39:04 -080067 Field(&addrinfo::ai_family, AF_UNSPEC),
Benjamin Fair30d09a32019-10-11 16:57:47 -070068 Field(&addrinfo::ai_socktype, SOCK_STREAM)),
69 NotNull()))
70 .WillOnce(DoAll(SetArgPointee<3>(&addr), Return(0)));
71 EXPECT_CALL(sysMock, freeaddrinfo(&addr));
72 }
73
74 void expectConnection()
75 {
76 EXPECT_CALL(sysMock, socket(AF_INET6, SOCK_STREAM, 0))
77 .WillOnce(Return(connFd));
78 EXPECT_CALL(sysMock, close(connFd)).WillOnce(Return(0));
79 EXPECT_CALL(sysMock,
80 connect(connFd, reinterpret_cast<struct sockaddr*>(&sa),
81 sizeof(sa)))
82 .WillOnce(Return(0));
83 }
84
85 internal::InternalSysMock sysMock;
86 ipmiblob::BlobInterfaceMock blobMock;
87 ProgressMock progMock;
88
89 const std::string host = "::1"s;
90 const std::string port = "622"s;
91
92 struct sockaddr_in6 sa;
93 struct addrinfo addr;
94
95 static constexpr std::uint16_t session = 0xbeef;
96 const std::string filePath = "/asdf"s;
97 static constexpr int inFd = 5;
98 static constexpr int connFd = 7;
99 static constexpr size_t fakeFileSize = 128;
100 static constexpr size_t chunkSize = 16;
101
102 NetDataHandler handler;
103};
104
105TEST_F(NetHandleTest, openFileFail)
106{
107 EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
108 .WillOnce(SetErrnoAndReturn(EACCES, -1));
109
110 EXPECT_FALSE(handler.sendContents(filePath, session));
111}
112
Benjamin Fair30d09a32019-10-11 16:57:47 -0700113TEST_F(NetHandleTest, getaddrinfoFail)
114{
115 expectOpenFile();
116
117 EXPECT_CALL(sysMock,
118 getaddrinfo(StrEq(host), StrEq(port),
119 AllOf(Field(&addrinfo::ai_flags, AI_NUMERICHOST),
Benjamin Fair2aa55342019-12-04 16:39:04 -0800120 Field(&addrinfo::ai_family, AF_UNSPEC),
Benjamin Fair30d09a32019-10-11 16:57:47 -0700121 Field(&addrinfo::ai_socktype, SOCK_STREAM)),
122 NotNull()))
123 .WillOnce(Return(EAI_ADDRFAMILY));
124
125 EXPECT_FALSE(handler.sendContents(filePath, session));
126}
127
128TEST_F(NetHandleTest, connectFail)
129{
130 expectOpenFile();
131 expectAddrInfo();
132
133 EXPECT_CALL(sysMock, socket(AF_INET6, SOCK_STREAM, 0))
134 .WillOnce(Return(connFd));
135 EXPECT_CALL(sysMock, close(connFd)).WillOnce(Return(0));
136 EXPECT_CALL(
137 sysMock,
138 connect(connFd, reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)))
139 .WillOnce(SetErrnoAndReturn(ECONNREFUSED, -1));
140
141 EXPECT_FALSE(handler.sendContents(filePath, session));
142}
143
144TEST_F(NetHandleTest, sendfileFail)
145{
146 expectOpenFile();
147 expectAddrInfo();
148 expectConnection();
149
150 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(0), _))
151 .WillOnce(SetErrnoAndReturn(ETIMEDOUT, -1));
152
153 EXPECT_FALSE(handler.sendContents(filePath, session));
154}
155
156TEST_F(NetHandleTest, successOneChunk)
157{
158 expectOpenFile();
159 expectAddrInfo();
160 expectConnection();
161
162 {
163 InSequence seq;
164
165 EXPECT_CALL(sysMock,
166 sendfile(connFd, inFd, Pointee(0), Gt(fakeFileSize)))
167 .WillOnce(
168 DoAll(SetArgPointee<2>(fakeFileSize), Return(fakeFileSize)));
169 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(fakeFileSize),
170 Gt(fakeFileSize)))
171 .WillOnce(Return(0));
172 }
173
174 struct ipmi_flash::ExtChunkHdr chunk;
175 chunk.length = fakeFileSize;
176 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
177 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
178 EXPECT_CALL(blobMock, writeBytes(session, 0, ContainerEq(chunkBytes)));
179
180 EXPECT_CALL(progMock, updateProgress(fakeFileSize));
181
182 EXPECT_TRUE(handler.sendContents(filePath, session));
183}
184
185TEST_F(NetHandleTest, successMultiChunk)
186{
187 expectOpenFile();
188 expectAddrInfo();
189 expectConnection();
190
191 struct ipmi_flash::ExtChunkHdr chunk;
192 chunk.length = chunkSize;
193 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
194 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
195
196 {
197 InSequence seq;
198
199 for (std::uint32_t offset = 0; offset < fakeFileSize;
200 offset += chunkSize)
201 {
202 EXPECT_CALL(sysMock,
203 sendfile(connFd, inFd, Pointee(offset), Gt(chunkSize)))
204 .WillOnce(DoAll(SetArgPointee<2>(offset + chunkSize),
205 Return(chunkSize)));
206
207 EXPECT_CALL(blobMock,
208 writeBytes(session, offset, ContainerEq(chunkBytes)));
209 EXPECT_CALL(progMock, updateProgress(chunkSize));
210 }
211 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(fakeFileSize),
212 Gt(chunkSize)))
213 .WillOnce(Return(0));
214 }
215
216 EXPECT_TRUE(handler.sendContents(filePath, session));
217}
218
219} // namespace
220} // namespace host_tool