1 #include "data.hpp" 2 #include "internal_sys_mock.hpp" 3 #include "net.hpp" 4 #include "progress_mock.hpp" 5 6 #include <ipmiblob/test/blob_interface_mock.hpp> 7 8 #include <cstring> 9 10 #include <gtest/gtest.h> 11 12 namespace host_tool 13 { 14 namespace 15 { 16 17 using namespace std::literals; 18 19 using ::testing::_; 20 using ::testing::AllOf; 21 using ::testing::ContainerEq; 22 using ::testing::DoAll; 23 using ::testing::Field; 24 using ::testing::Gt; 25 using ::testing::InSequence; 26 using ::testing::NotNull; 27 using ::testing::Pointee; 28 using ::testing::Return; 29 using ::testing::SetArgPointee; 30 using ::testing::SetErrnoAndReturn; 31 using ::testing::StrEq; 32 33 class 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 61 void expectAddrInfo() 62 { 63 EXPECT_CALL( 64 sysMock, 65 getaddrinfo(StrEq(host), StrEq(port), 66 AllOf(Field(&addrinfo::ai_flags, AI_NUMERICHOST), 67 Field(&addrinfo::ai_family, AF_UNSPEC), 68 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 105 TEST_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 113 TEST_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 123 TEST_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), 130 Field(&addrinfo::ai_family, AF_UNSPEC), 131 Field(&addrinfo::ai_socktype, SOCK_STREAM)), 132 NotNull())) 133 .WillOnce(Return(EAI_ADDRFAMILY)); 134 135 EXPECT_FALSE(handler.sendContents(filePath, session)); 136 } 137 138 TEST_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 154 TEST_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 166 TEST_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 195 TEST_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 231