1 /** 2 * The goal of these tests is to verify the behavior of all blob commands given 3 * the current state is verificationPending. This state is achieved as a 4 * transition out of uploadInProgress. 5 */ 6 #include "firmware_handler.hpp" 7 #include "firmware_unittest.hpp" 8 #include "status.hpp" 9 #include "util.hpp" 10 11 #include <algorithm> 12 #include <cstdint> 13 #include <string> 14 #include <vector> 15 16 #include <gtest/gtest.h> 17 18 namespace ipmi_flash 19 { 20 namespace 21 { 22 23 using ::testing::IsEmpty; 24 using ::testing::Return; 25 using ::testing::UnorderedElementsAreArray; 26 27 /* 28 * There are the following calls (parameters may vary): 29 * canHandleBlob(blob) 30 * getBlobIds 31 * deleteBlob(blob) 32 * stat(blob) 33 * stat(session) 34 * open(blob) 35 * close(session) 36 * writemeta(session) 37 * write(session) 38 * read(session) 39 * commit(session) 40 * 41 * Testing canHandleBlob is uninteresting in this state. Getting the BlobIDs 42 * will inform what canHandleBlob will return. 43 */ 44 45 class FirmwareHandlerVerificationPendingTest : public IpmiOnlyFirmwareStaticTest 46 {}; 47 48 /* 49 * getBlobIds 50 */ 51 TEST_F(FirmwareHandlerVerificationPendingTest, VerifyBlobIdAvailableInState) 52 { 53 /* Only in the verificationPending state (and later), should the 54 * verifyBlobId be present. 55 */ 56 EXPECT_FALSE(handler->canHandleBlob(verifyBlobId)); 57 58 getToVerificationPending(staticLayoutBlobId); 59 60 EXPECT_TRUE(handler->canHandleBlob(verifyBlobId)); 61 EXPECT_TRUE(handler->canHandleBlob(activeImageBlobId)); 62 EXPECT_FALSE(handler->canHandleBlob(updateBlobId)); 63 } 64 65 /* 66 * delete(blob) 67 */ 68 TEST_F(FirmwareHandlerVerificationPendingTest, DeleteVerifyPendingAbortsProcess) 69 { 70 /* It doesn't matter what blob id is used to delete in the design, so just 71 * delete the verify blob id 72 */ 73 getToVerificationPending(staticLayoutBlobId); 74 75 EXPECT_CALL(*verifyMockPtr, abort()).Times(0); 76 77 ASSERT_TRUE(handler->canHandleBlob(verifyBlobId)); 78 EXPECT_TRUE(handler->deleteBlob(verifyBlobId)); 79 80 std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId}; 81 EXPECT_THAT(handler->getBlobIds(), 82 UnorderedElementsAreArray(expectedBlobs)); 83 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 84 } 85 86 TEST_F(FirmwareHandlerVerificationPendingTest, DeleteActiveImageAbortsProcess) 87 { 88 getToVerificationPending(staticLayoutBlobId); 89 90 EXPECT_CALL(*verifyMockPtr, abort()).Times(0); 91 92 ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId)); 93 EXPECT_TRUE(handler->deleteBlob(activeImageBlobId)); 94 95 std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId}; 96 EXPECT_THAT(handler->getBlobIds(), 97 UnorderedElementsAreArray(expectedBlobs)); 98 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 99 } 100 101 TEST_F(FirmwareHandlerVerificationPendingTest, DeleteStaticLayoutAbortsProcess) 102 { 103 getToVerificationPending(staticLayoutBlobId); 104 105 EXPECT_CALL(*verifyMockPtr, abort()).Times(0); 106 107 ASSERT_TRUE(handler->canHandleBlob(staticLayoutBlobId)); 108 EXPECT_TRUE(handler->deleteBlob(staticLayoutBlobId)); 109 110 std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId}; 111 EXPECT_THAT(handler->getBlobIds(), 112 UnorderedElementsAreArray(expectedBlobs)); 113 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 114 } 115 116 TEST_F(FirmwareHandlerVerificationPendingTest, DeleteHashAbortsProcess) 117 { 118 getToVerificationPending(staticLayoutBlobId); 119 120 EXPECT_CALL(*verifyMockPtr, abort()).Times(0); 121 122 ASSERT_TRUE(handler->canHandleBlob(hashBlobId)); 123 EXPECT_TRUE(handler->deleteBlob(hashBlobId)); 124 125 std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId}; 126 EXPECT_THAT(handler->getBlobIds(), 127 UnorderedElementsAreArray(expectedBlobs)); 128 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 129 } 130 131 /* 132 * expire(session) 133 */ 134 TEST_F(FirmwareHandlerVerificationPendingTest, 135 ExpireVerificationPendingAbortsProcess) 136 { 137 getToVerificationPending(staticLayoutBlobId); 138 139 EXPECT_CALL(*verifyMockPtr, abort()).Times(0); 140 141 EXPECT_TRUE(handler->expire(session)); 142 143 std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId}; 144 EXPECT_THAT(handler->getBlobIds(), 145 UnorderedElementsAreArray(expectedBlobs)); 146 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 147 } 148 149 /* 150 * stat(blob) 151 */ 152 TEST_F(FirmwareHandlerVerificationPendingTest, StatOnActiveImageReturnsFailure) 153 { 154 getToVerificationPending(staticLayoutBlobId); 155 ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId)); 156 157 blobs::BlobMeta meta; 158 EXPECT_FALSE(handler->stat(activeImageBlobId, &meta)); 159 } 160 161 TEST_F(FirmwareHandlerVerificationPendingTest, StatOnActiveHashReturnsFailure) 162 { 163 getToVerificationPending(hashBlobId); 164 ASSERT_TRUE(handler->canHandleBlob(activeHashBlobId)); 165 166 blobs::BlobMeta meta; 167 EXPECT_FALSE(handler->stat(activeHashBlobId, &meta)); 168 } 169 170 TEST_F(FirmwareHandlerVerificationPendingTest, 171 StatOnVerificationBlobReturnsFailure) 172 { 173 getToVerificationPending(staticLayoutBlobId); 174 ASSERT_TRUE(handler->canHandleBlob(verifyBlobId)); 175 176 blobs::BlobMeta meta; 177 EXPECT_FALSE(handler->stat(verifyBlobId, &meta)); 178 } 179 180 TEST_F(FirmwareHandlerVerificationPendingTest, 181 VerificationBlobNotFoundWithoutStaticDataAsWell) 182 { 183 /* If you only ever open the hash blob id, and never the firmware blob id, 184 * the verify blob isn't added. 185 */ 186 getToVerificationPending(hashBlobId); 187 EXPECT_FALSE(handler->canHandleBlob(verifyBlobId)); 188 } 189 190 TEST_F(FirmwareHandlerVerificationPendingTest, StatOnNormalBlobsReturnsSuccess) 191 { 192 getToVerificationPending(staticLayoutBlobId); 193 194 std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId}; 195 for (const auto& blob : testBlobs) 196 { 197 ASSERT_TRUE(handler->canHandleBlob(blob)); 198 blobs::BlobMeta meta = {}; 199 EXPECT_TRUE(handler->stat(blob, &meta)); 200 EXPECT_EQ(expectedIdleMeta, meta); 201 } 202 } 203 204 /* 205 * open(blob) 206 */ 207 TEST_F(FirmwareHandlerVerificationPendingTest, OpenVerifyBlobSucceeds) 208 { 209 getToVerificationPending(staticLayoutBlobId); 210 211 /* the session is safe because it was already closed to get to this state. 212 */ 213 EXPECT_TRUE(handler->open(session, flags, verifyBlobId)); 214 } 215 216 TEST_F(FirmwareHandlerVerificationPendingTest, OpenActiveBlobsFail) 217 { 218 /* Try opening the active blob Id. This test is equivalent to trying to 219 * open the active hash blob id, in that neither are ever allowed. 220 */ 221 getToVerificationPending(staticLayoutBlobId); 222 EXPECT_FALSE(handler->open(session, flags, activeImageBlobId)); 223 EXPECT_FALSE(handler->open(session, flags, activeHashBlobId)); 224 } 225 226 TEST_F(FirmwareHandlerVerificationPendingTest, 227 OpenImageBlobTransitionsToUploadInProgress) 228 { 229 getToVerificationPending(staticLayoutBlobId); 230 231 /* Verify the active blob for the image is in the list once to start. 232 * Note: This is truly tested under the notYetStarted::open() test. 233 */ 234 std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId, 235 verifyBlobId, activeImageBlobId}; 236 237 EXPECT_THAT(handler->getBlobIds(), 238 UnorderedElementsAreArray(expectedBlobs)); 239 240 /* Verifies it isn't triggered again. */ 241 EXPECT_CALL(*prepareMockPtr, trigger()).Times(0); 242 243 EXPECT_CALL(*imageMock2, open(staticLayoutBlobId, std::ios::out)) 244 .WillOnce(Return(true)); 245 EXPECT_TRUE(handler->open(session, flags, staticLayoutBlobId)); 246 expectedState(FirmwareBlobHandler::UpdateState::uploadInProgress); 247 248 expectedBlobs.erase( 249 std::remove(expectedBlobs.begin(), expectedBlobs.end(), verifyBlobId), 250 expectedBlobs.end()); 251 252 /* Verify the active blob ID was not added to the list twice and 253 * verifyBlobId is removed 254 */ 255 EXPECT_THAT(handler->getBlobIds(), 256 UnorderedElementsAreArray(expectedBlobs)); 257 } 258 259 /* 260 * close(session) 261 */ 262 TEST_F(FirmwareHandlerVerificationPendingTest, 263 ClosingVerifyBlobWithoutCommitDoesNotChangeState) 264 { 265 /* commit() will change the state, closing post-commit is part of 266 * verificationStarted testing. 267 */ 268 getToVerificationPending(staticLayoutBlobId); 269 EXPECT_TRUE(handler->open(session, flags, verifyBlobId)); 270 expectedState(FirmwareBlobHandler::UpdateState::verificationPending); 271 272 handler->close(session); 273 expectedState(FirmwareBlobHandler::UpdateState::verificationPending); 274 } 275 276 /* 277 * commit(session) 278 */ 279 TEST_F(FirmwareHandlerVerificationPendingTest, 280 CommitOnVerifyBlobTriggersVerificationAndStateTransition) 281 { 282 getToVerificationPending(staticLayoutBlobId); 283 EXPECT_TRUE(handler->open(session, flags, verifyBlobId)); 284 EXPECT_CALL(*verifyMockPtr, trigger()).WillOnce(Return(true)); 285 286 EXPECT_TRUE(handler->commit(session, {})); 287 expectedState(FirmwareBlobHandler::UpdateState::verificationStarted); 288 } 289 290 /* 291 * stat(session) - in this state, you can only open(verifyBlobId) without 292 * changing state. 293 */ 294 TEST_F(FirmwareHandlerVerificationPendingTest, StatOnVerifyBlobIdReturnsState) 295 { 296 /* If this is called before commit(), it's still verificationPending, so it 297 * just returns the state is other 298 */ 299 getToVerificationPending(staticLayoutBlobId); 300 EXPECT_TRUE(handler->open(session, flags, verifyBlobId)); 301 EXPECT_CALL(*verifyMockPtr, trigger()).Times(0); 302 EXPECT_CALL(*verifyMockPtr, status()).Times(0); 303 304 blobs::BlobMeta meta, expectedMeta = {}; 305 expectedMeta.size = 0; 306 expectedMeta.blobState = flags; 307 expectedMeta.metadata.push_back( 308 static_cast<std::uint8_t>(ActionStatus::unknown)); 309 310 EXPECT_TRUE(handler->stat(session, &meta)); 311 EXPECT_EQ(expectedMeta, meta); 312 } 313 314 /* 315 * writemeta(session) 316 */ 317 TEST_F(FirmwareHandlerVerificationPendingTest, WriteMetaAgainstVerifyFails) 318 { 319 /* The verifyBlobId has no data handler, which means write meta fails. */ 320 getToVerificationPending(staticLayoutBlobId); 321 322 EXPECT_TRUE(handler->open(session, flags, verifyBlobId)); 323 324 std::vector<std::uint8_t> bytes = {0x01, 0x02}; 325 EXPECT_FALSE(handler->writeMeta(session, 0, bytes)); 326 } 327 328 /* 329 * write(session) 330 */ 331 TEST_F(FirmwareHandlerVerificationPendingTest, WriteAgainstVerifyBlobIdFails) 332 { 333 getToVerificationPending(staticLayoutBlobId); 334 335 EXPECT_TRUE(handler->open(session, flags, verifyBlobId)); 336 337 std::vector<std::uint8_t> bytes = {0x01, 0x02}; 338 EXPECT_FALSE(handler->write(session, 0, bytes)); 339 } 340 341 /* 342 * read(session) 343 */ 344 TEST_F(FirmwareHandlerVerificationPendingTest, 345 ReadAgainstVerifyBlobIdReturnsEmpty) 346 { 347 getToVerificationPending(staticLayoutBlobId); 348 349 EXPECT_TRUE(handler->open(session, flags, verifyBlobId)); 350 EXPECT_THAT(handler->read(session, 0, 1), IsEmpty()); 351 } 352 353 } // namespace 354 } // namespace ipmi_flash 355