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