1 #include "data_interface_mock.hpp" 2 #include "flags.hpp" 3 #include "status.hpp" 4 #include "tool_errors.hpp" 5 #include "updater.hpp" 6 #include "updater_mock.hpp" 7 #include "util.hpp" 8 9 #include <ipmiblob/blob_errors.hpp> 10 #include <ipmiblob/test/blob_interface_mock.hpp> 11 12 #include <string> 13 #include <vector> 14 15 #include <gmock/gmock.h> 16 #include <gtest/gtest.h> 17 18 namespace host_tool 19 { 20 21 using ::testing::_; 22 using ::testing::Eq; 23 using ::testing::Return; 24 using ::testing::Throw; 25 using ::testing::TypedEq; 26 27 class UpdateHandlerTest : public ::testing::Test 28 { 29 protected: 30 const std::uint16_t session = 0xbeef; 31 32 DataInterfaceMock handlerMock; 33 ipmiblob::BlobInterfaceMock blobMock; 34 UpdateHandler updater{&blobMock, &handlerMock}; 35 }; 36 37 TEST_F(UpdateHandlerTest, CheckAvailableSuccess) 38 { 39 EXPECT_CALL(blobMock, getBlobList()) 40 .WillOnce( 41 Return(std::vector<std::string>({ipmi_flash::staticLayoutBlobId}))); 42 43 EXPECT_TRUE(updater.checkAvailable(ipmi_flash::staticLayoutBlobId)); 44 } 45 46 TEST_F(UpdateHandlerTest, CheckAvailableFailure) 47 { 48 EXPECT_CALL(blobMock, getBlobList()) 49 .WillOnce(Return(std::vector<std::string>())); 50 51 EXPECT_FALSE(updater.checkAvailable(ipmi_flash::staticLayoutBlobId)); 52 } 53 54 TEST_F(UpdateHandlerTest, SendFileSuccess) 55 { 56 /* Call sendFile to verify it does what we expect. */ 57 std::string firmwareImage = "image.bin"; 58 59 std::uint16_t supported = 60 static_cast<std::uint16_t>( 61 ipmi_flash::FirmwareFlags::UpdateFlags::lpc) | 62 static_cast<std::uint16_t>( 63 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite); 64 65 EXPECT_CALL(handlerMock, supportedType()) 66 .WillOnce(Return(ipmi_flash::FirmwareFlags::UpdateFlags::lpc)); 67 68 EXPECT_CALL(blobMock, openBlob(ipmi_flash::staticLayoutBlobId, supported)) 69 .WillOnce(Return(session)); 70 71 EXPECT_CALL(handlerMock, sendContents(firmwareImage, session)) 72 .WillOnce(Return(true)); 73 74 EXPECT_CALL(blobMock, closeBlob(session)).Times(1); 75 76 updater.sendFile(ipmi_flash::staticLayoutBlobId, firmwareImage); 77 } 78 79 TEST_F(UpdateHandlerTest, SendFileExceptsOnBlobOpening) 80 { 81 std::string firmwareImage = "image.bin"; 82 83 std::uint16_t supported = 84 static_cast<std::uint16_t>( 85 ipmi_flash::FirmwareFlags::UpdateFlags::lpc) | 86 static_cast<std::uint16_t>( 87 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite); 88 89 EXPECT_CALL(handlerMock, supportedType()) 90 .WillOnce(Return(ipmi_flash::FirmwareFlags::UpdateFlags::lpc)); 91 92 EXPECT_CALL(blobMock, openBlob(ipmi_flash::staticLayoutBlobId, supported)) 93 .WillOnce(Throw(ipmiblob::BlobException("asdf"))); 94 95 EXPECT_THROW( 96 updater.sendFile(ipmi_flash::staticLayoutBlobId, firmwareImage), 97 ToolException); 98 } 99 100 TEST_F(UpdateHandlerTest, SendFileHandlerFailureCausesException) 101 { 102 std::string firmwareImage = "image.bin"; 103 104 std::uint16_t supported = 105 static_cast<std::uint16_t>( 106 ipmi_flash::FirmwareFlags::UpdateFlags::lpc) | 107 static_cast<std::uint16_t>( 108 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite); 109 110 EXPECT_CALL(handlerMock, supportedType()) 111 .WillOnce(Return(ipmi_flash::FirmwareFlags::UpdateFlags::lpc)); 112 113 EXPECT_CALL(blobMock, openBlob(ipmi_flash::staticLayoutBlobId, supported)) 114 .WillOnce(Return(session)); 115 116 EXPECT_CALL(handlerMock, sendContents(firmwareImage, session)) 117 .WillOnce(Return(false)); 118 119 EXPECT_CALL(blobMock, closeBlob(session)).Times(1); 120 121 EXPECT_THROW( 122 updater.sendFile(ipmi_flash::staticLayoutBlobId, firmwareImage), 123 ToolException); 124 } 125 126 TEST_F(UpdateHandlerTest, VerifyFileHandleReturnsTrueOnSuccess) 127 { 128 EXPECT_CALL(blobMock, openBlob(ipmi_flash::verifyBlobId, _)) 129 .WillOnce(Return(session)); 130 EXPECT_CALL(blobMock, commit(session, _)).WillOnce(Return()); 131 ipmiblob::StatResponse verificationResponse = {}; 132 /* the other details of the response are ignored, and should be. */ 133 verificationResponse.metadata.push_back( 134 static_cast<std::uint8_t>(ipmi_flash::ActionStatus::success)); 135 136 EXPECT_CALL(blobMock, getStat(TypedEq<std::uint16_t>(session))) 137 .WillOnce(Return(verificationResponse)); 138 EXPECT_CALL(blobMock, closeBlob(session)).WillOnce(Return()); 139 140 EXPECT_TRUE(updater.verifyFile(ipmi_flash::verifyBlobId, false)); 141 } 142 143 TEST_F(UpdateHandlerTest, VerifyFileHandleSkipsPollingIfIgnoreStatus) 144 { 145 /* if ignoreStatus, it'll skip polling for a verification result. */ 146 EXPECT_CALL(blobMock, openBlob(ipmi_flash::verifyBlobId, _)) 147 .WillOnce(Return(session)); 148 EXPECT_CALL(blobMock, commit(session, _)).WillOnce(Return()); 149 150 EXPECT_CALL(blobMock, closeBlob(session)).WillOnce(Return()); 151 152 EXPECT_TRUE(updater.verifyFile(ipmi_flash::verifyBlobId, true)); 153 } 154 155 TEST_F(UpdateHandlerTest, VerifyFileConvertsOpenBlobExceptionToToolException) 156 { 157 /* On open, it can except and this is converted to a ToolException. */ 158 EXPECT_CALL(blobMock, openBlob(ipmi_flash::verifyBlobId, _)) 159 .WillOnce(Throw(ipmiblob::BlobException("asdf"))); 160 EXPECT_THROW(updater.verifyFile(ipmi_flash::verifyBlobId, false), 161 ToolException); 162 } 163 164 TEST_F(UpdateHandlerTest, VerifyFileCommitExceptionForwards) 165 { 166 /* On commit, it can except. */ 167 EXPECT_CALL(blobMock, openBlob(ipmi_flash::verifyBlobId, _)) 168 .WillOnce(Return(session)); 169 EXPECT_CALL(blobMock, commit(session, _)) 170 .WillOnce(Throw(ipmiblob::BlobException("asdf"))); 171 EXPECT_THROW(updater.verifyFile(ipmi_flash::verifyBlobId, false), 172 ToolException); 173 } 174 175 TEST_F(UpdateHandlerTest, CleanArtifactsSkipsCleanupIfUnableToOpen) 176 { 177 /* It only tries to commit if it's able to open the blob. However, if 178 * committing fails, this error is ignored. 179 */ 180 EXPECT_CALL(blobMock, openBlob(ipmi_flash::cleanupBlobId, _)) 181 .WillOnce(Throw(ipmiblob::BlobException("asdf"))); 182 EXPECT_CALL(blobMock, commit(_, _)).Times(0); 183 EXPECT_CALL(blobMock, closeBlob(_)).Times(0); 184 185 updater.cleanArtifacts(); 186 } 187 188 TEST_F(UpdateHandlerTest, CleanArtifactsIfOpenDoesClose) 189 { 190 /* The closeBlob call is called even if commit excepts. */ 191 std::uint16_t session = 0xa5eb; 192 EXPECT_CALL(blobMock, openBlob(ipmi_flash::cleanupBlobId, _)) 193 .WillOnce(Return(session)); 194 EXPECT_CALL(blobMock, commit(session, _)) 195 .WillOnce(Throw(ipmiblob::BlobException("asdf"))); 196 EXPECT_CALL(blobMock, closeBlob(session)); 197 198 updater.cleanArtifacts(); 199 } 200 201 TEST_F(UpdateHandlerTest, CleanArtifactsSuccessPath) 202 { 203 std::uint16_t session = 0xa5eb; 204 EXPECT_CALL(blobMock, openBlob(ipmi_flash::cleanupBlobId, _)) 205 .WillOnce(Return(session)); 206 EXPECT_CALL(blobMock, commit(session, _)); 207 EXPECT_CALL(blobMock, closeBlob(session)); 208 209 updater.cleanArtifacts(); 210 } 211 212 class UpdaterTest : public ::testing::Test 213 { 214 protected: 215 static constexpr char image[] = "image.bin"; 216 static constexpr char signature[] = "signature.bin"; 217 static constexpr char layout[] = "static"; 218 static constexpr char path[] = "/flash/static"; 219 220 ipmiblob::BlobInterfaceMock blobMock; 221 std::uint16_t session = 0xbeef; 222 bool defaultIgnore = false; 223 }; 224 225 TEST_F(UpdaterTest, UpdateMainReturnsSuccessIfAllSuccess) 226 { 227 UpdateHandlerMock handler; 228 229 EXPECT_CALL(handler, checkAvailable(path)).WillOnce(Return(true)); 230 EXPECT_CALL(handler, sendFile(path, image)).WillOnce(Return()); 231 EXPECT_CALL(handler, sendFile(ipmi_flash::hashBlobId, signature)) 232 .WillOnce(Return()); 233 EXPECT_CALL(handler, verifyFile(ipmi_flash::verifyBlobId, defaultIgnore)) 234 .WillOnce(Return(true)); 235 EXPECT_CALL(handler, verifyFile(ipmi_flash::updateBlobId, defaultIgnore)) 236 .WillOnce(Return(true)); 237 238 updaterMain(&handler, image, signature, layout, defaultIgnore); 239 } 240 241 TEST_F(UpdaterTest, UpdateMainReturnsSuccessWithIgnoreUpdate) 242 { 243 UpdateHandlerMock handler; 244 bool updateIgnore = true; 245 246 EXPECT_CALL(handler, checkAvailable(path)).WillOnce(Return(true)); 247 EXPECT_CALL(handler, sendFile(path, image)).WillOnce(Return()); 248 EXPECT_CALL(handler, sendFile(ipmi_flash::hashBlobId, signature)) 249 .WillOnce(Return()); 250 EXPECT_CALL(handler, verifyFile(ipmi_flash::verifyBlobId, defaultIgnore)) 251 .WillOnce(Return(true)); 252 EXPECT_CALL(handler, verifyFile(ipmi_flash::updateBlobId, updateIgnore)) 253 .WillOnce(Return(true)); 254 255 updaterMain(&handler, image, signature, layout, updateIgnore); 256 } 257 258 TEST_F(UpdaterTest, UpdateMainCleansUpOnFailure) 259 { 260 UpdateHandlerMock handler; 261 262 EXPECT_CALL(handler, checkAvailable(path)).WillOnce(Return(true)); 263 EXPECT_CALL(handler, sendFile(path, image)).WillOnce(Return()); 264 EXPECT_CALL(handler, sendFile(ipmi_flash::hashBlobId, signature)) 265 .WillOnce(Return()); 266 EXPECT_CALL(handler, verifyFile(ipmi_flash::verifyBlobId, defaultIgnore)) 267 .WillOnce(Return(false)); 268 EXPECT_CALL(handler, cleanArtifacts()).WillOnce(Return()); 269 270 EXPECT_THROW(updaterMain(&handler, image, signature, layout, defaultIgnore), 271 ToolException); 272 } 273 274 TEST_F(UpdaterTest, UpdateMainExceptsOnUpdateBlobFailure) 275 { 276 UpdateHandlerMock handler; 277 278 EXPECT_CALL(handler, checkAvailable(path)).WillOnce(Return(true)); 279 EXPECT_CALL(handler, sendFile(path, image)).WillOnce(Return()); 280 EXPECT_CALL(handler, sendFile(ipmi_flash::hashBlobId, signature)) 281 .WillOnce(Return()); 282 EXPECT_CALL(handler, verifyFile(ipmi_flash::verifyBlobId, defaultIgnore)) 283 .WillOnce(Return(true)); 284 EXPECT_CALL(handler, verifyFile(ipmi_flash::updateBlobId, defaultIgnore)) 285 .WillOnce(Return(false)); 286 EXPECT_CALL(handler, cleanArtifacts()).WillOnce(Return()); 287 288 EXPECT_THROW(updaterMain(&handler, image, signature, layout, defaultIgnore), 289 ToolException); 290 } 291 292 TEST_F(UpdaterTest, UpdateMainExceptsIfAvailableNotFound) 293 { 294 UpdateHandlerMock handler; 295 296 EXPECT_CALL(handler, checkAvailable(path)).WillOnce(Return(false)); 297 298 EXPECT_THROW(updaterMain(&handler, image, signature, layout, defaultIgnore), 299 ToolException); 300 } 301 302 } // namespace host_tool 303