blob: c5b841905bc3631498d12d03211ffbaa17afefb0 [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
6#include <cstring>
7#include <ipmiblob/test/blob_interface_mock.hpp>
8
9#include <gtest/gtest.h>
10
11namespace host_tool
12{
13namespace
14{
15
16using namespace std::literals;
17
18using ::testing::_;
19using ::testing::AllOf;
20using ::testing::ContainerEq;
Rui Zhang382d2a02020-03-25 11:12:30 -070021using ::testing::DoAll;
Benjamin Fair30d09a32019-10-11 16:57:47 -070022using ::testing::Field;
23using ::testing::Gt;
24using ::testing::InSequence;
25using ::testing::NotNull;
26using ::testing::Pointee;
27using ::testing::Return;
28using ::testing::SetArgPointee;
29using ::testing::SetErrnoAndReturn;
30using ::testing::StrEq;
31
32class NetHandleTest : public ::testing::Test
33{
34 protected:
35 NetHandleTest() : handler(&blobMock, &progMock, host, port, &sysMock)
36 {
37 sa.sin6_family = AF_INET6;
38 sa.sin6_port = htons(622);
39 sa.sin6_flowinfo = 0;
40 sa.sin6_addr = in6addr_loopback; // ::1
41 sa.sin6_scope_id = 0;
42
43 addr.ai_family = AF_INET6;
44 addr.ai_socktype = SOCK_STREAM;
45 addr.ai_addr = reinterpret_cast<struct sockaddr*>(&sa);
46 addr.ai_addrlen = sizeof(sa);
47 addr.ai_protocol = 0;
48 addr.ai_next = nullptr;
49 }
50
51 void expectOpenFile()
52 {
53 EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
54 .WillOnce(Return(inFd));
55 EXPECT_CALL(sysMock, close(inFd)).WillOnce(Return(0));
56 EXPECT_CALL(sysMock, getSize(StrEq(filePath.c_str())))
57 .WillOnce(Return(fakeFileSize));
58
59 EXPECT_CALL(progMock, start(fakeFileSize));
60 }
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
114TEST_F(NetHandleTest, getSizeFail)
115{
116 EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _))
117 .WillOnce(Return(inFd));
118 EXPECT_CALL(sysMock, close(inFd)).WillOnce(Return(0));
119 EXPECT_CALL(sysMock, getSize(StrEq(filePath.c_str()))).WillOnce(Return(0));
120
121 EXPECT_FALSE(handler.sendContents(filePath, session));
122}
123
124TEST_F(NetHandleTest, getaddrinfoFail)
125{
126 expectOpenFile();
127
128 EXPECT_CALL(sysMock,
129 getaddrinfo(StrEq(host), StrEq(port),
130 AllOf(Field(&addrinfo::ai_flags, AI_NUMERICHOST),
Benjamin Fair2aa55342019-12-04 16:39:04 -0800131 Field(&addrinfo::ai_family, AF_UNSPEC),
Benjamin Fair30d09a32019-10-11 16:57:47 -0700132 Field(&addrinfo::ai_socktype, SOCK_STREAM)),
133 NotNull()))
134 .WillOnce(Return(EAI_ADDRFAMILY));
135
136 EXPECT_FALSE(handler.sendContents(filePath, session));
137}
138
139TEST_F(NetHandleTest, connectFail)
140{
141 expectOpenFile();
142 expectAddrInfo();
143
144 EXPECT_CALL(sysMock, socket(AF_INET6, SOCK_STREAM, 0))
145 .WillOnce(Return(connFd));
146 EXPECT_CALL(sysMock, close(connFd)).WillOnce(Return(0));
147 EXPECT_CALL(
148 sysMock,
149 connect(connFd, reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)))
150 .WillOnce(SetErrnoAndReturn(ECONNREFUSED, -1));
151
152 EXPECT_FALSE(handler.sendContents(filePath, session));
153}
154
155TEST_F(NetHandleTest, sendfileFail)
156{
157 expectOpenFile();
158 expectAddrInfo();
159 expectConnection();
160
161 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(0), _))
162 .WillOnce(SetErrnoAndReturn(ETIMEDOUT, -1));
163
164 EXPECT_FALSE(handler.sendContents(filePath, session));
165}
166
167TEST_F(NetHandleTest, successOneChunk)
168{
169 expectOpenFile();
170 expectAddrInfo();
171 expectConnection();
172
173 {
174 InSequence seq;
175
176 EXPECT_CALL(sysMock,
177 sendfile(connFd, inFd, Pointee(0), Gt(fakeFileSize)))
178 .WillOnce(
179 DoAll(SetArgPointee<2>(fakeFileSize), Return(fakeFileSize)));
180 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(fakeFileSize),
181 Gt(fakeFileSize)))
182 .WillOnce(Return(0));
183 }
184
185 struct ipmi_flash::ExtChunkHdr chunk;
186 chunk.length = fakeFileSize;
187 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
188 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
189 EXPECT_CALL(blobMock, writeBytes(session, 0, ContainerEq(chunkBytes)));
190
191 EXPECT_CALL(progMock, updateProgress(fakeFileSize));
192
193 EXPECT_TRUE(handler.sendContents(filePath, session));
194}
195
196TEST_F(NetHandleTest, successMultiChunk)
197{
198 expectOpenFile();
199 expectAddrInfo();
200 expectConnection();
201
202 struct ipmi_flash::ExtChunkHdr chunk;
203 chunk.length = chunkSize;
204 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
205 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
206
207 {
208 InSequence seq;
209
210 for (std::uint32_t offset = 0; offset < fakeFileSize;
211 offset += chunkSize)
212 {
213 EXPECT_CALL(sysMock,
214 sendfile(connFd, inFd, Pointee(offset), Gt(chunkSize)))
215 .WillOnce(DoAll(SetArgPointee<2>(offset + chunkSize),
216 Return(chunkSize)));
217
218 EXPECT_CALL(blobMock,
219 writeBytes(session, offset, ContainerEq(chunkBytes)));
220 EXPECT_CALL(progMock, updateProgress(chunkSize));
221 }
222 EXPECT_CALL(sysMock, sendfile(connFd, inFd, Pointee(fakeFileSize),
223 Gt(chunkSize)))
224 .WillOnce(Return(0));
225 }
226
227 EXPECT_TRUE(handler.sendContents(filePath, session));
228}
229
230} // namespace
231} // namespace host_tool