1 /** 2 * The goal of these tests is to verify the behavior of all blob commands given 3 * the current state is verificationCompleted. This state is achieved as a out 4 * of verificationStarted. 5 */ 6 #include "firmware_handler.hpp" 7 #include "firmware_unittest.hpp" 8 #include "status.hpp" 9 #include "util.hpp" 10 11 #include <cstdint> 12 #include <string> 13 #include <vector> 14 15 #include <gtest/gtest.h> 16 17 namespace ipmi_flash 18 { 19 namespace 20 { 21 22 using ::testing::IsEmpty; 23 using ::testing::UnorderedElementsAreArray; 24 25 /* 26 * There are the following calls (parameters may vary): 27 * canHandleBlob(blob) 28 * getBlobIds 29 * deleteBlob(blob) 30 * stat(blob) 31 * stat(session) 32 * open(blob) 33 * close(session) 34 * writemeta(session) 35 * write(session) 36 * read(session) 37 * commit(session) 38 * 39 * Like the state verificationStarted, there is a file open in 40 * verificationCompleted. This state is transitioned to after a stat() command 41 * indicates a successful verification. 42 */ 43 44 class FirmwareHandlerVerificationCompletedTest : 45 public IpmiOnlyFirmwareStaticTest 46 {}; 47 48 /* 49 * deleteBlob(blob) 50 */ 51 TEST_F(FirmwareHandlerVerificationCompletedTest, DeleteBlobReturnsFalse) 52 { 53 /* Try deleting all blobs, it doesn't really matter which though because you 54 * cannot close out an open session, therefore you must fail to delete 55 * anything unless everything is closed. 56 */ 57 getToVerificationCompleted(ActionStatus::success); 58 auto blobs = handler->getBlobIds(); 59 for (const auto& b : blobs) 60 { 61 EXPECT_FALSE(handler->deleteBlob(b)); 62 } 63 } 64 65 /* 66 * canHandleBlob 67 */ 68 TEST_F(FirmwareHandlerVerificationCompletedTest, 69 OnVerificationCompleteSuccessUpdateBlobIdNotPresent) 70 { 71 /* the uploadBlobId is only added on close() of the verifyBlobId. This is a 72 * consistent behavior with verifyBlobId only added when closing the image 73 * or hash. 74 */ 75 getToVerificationCompleted(ActionStatus::success); 76 EXPECT_FALSE(handler->canHandleBlob(updateBlobId)); 77 } 78 79 TEST_F(FirmwareHandlerVerificationCompletedTest, 80 OnVerificationCompleteFailureUpdateBlobIdNotPresent) 81 { 82 getToVerificationCompleted(ActionStatus::failed); 83 EXPECT_FALSE(handler->canHandleBlob(updateBlobId)); 84 } 85 86 /* 87 * getBlobIds 88 */ 89 TEST_F(FirmwareHandlerVerificationCompletedTest, GetBlobIdsReturnsExpectedList) 90 { 91 getToVerificationCompleted(ActionStatus::success); 92 EXPECT_THAT( 93 handler->getBlobIds(), 94 UnorderedElementsAreArray( 95 {verifyBlobId, hashBlobId, activeImageBlobId, staticLayoutBlobId})); 96 } 97 98 /* 99 * stat(blob) 100 */ 101 TEST_F(FirmwareHandlerVerificationCompletedTest, 102 StatOnActiveImageReturnsFailure) 103 { 104 getToVerificationCompleted(ActionStatus::success); 105 ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId)); 106 107 blobs::BlobMeta meta; 108 EXPECT_FALSE(handler->stat(activeImageBlobId, &meta)); 109 } 110 111 TEST_F(FirmwareHandlerVerificationCompletedTest, 112 VerifyActiveHashIdMissingInThisCase) 113 { 114 /* The path taken to get to this state never opened the hash blob Id, which 115 * is fine. But let's verify it behaved as intended. 116 */ 117 getToVerificationCompleted(ActionStatus::success); 118 EXPECT_FALSE(handler->canHandleBlob(activeHashBlobId)); 119 } 120 121 /* TODO: Add sufficient warning that you can get to verificationCompleted 122 * without ever opening the image blob id (or the tarball one). 123 * 124 * Although in this case, it's expected that any verification triggered would 125 * certainly fail. So, although it's possible, it's uninteresting. 126 */ 127 128 TEST_F(FirmwareHandlerVerificationCompletedTest, StatOnVerifyBlobReturnsFailure) 129 { 130 getToVerificationCompleted(ActionStatus::success); 131 ASSERT_TRUE(handler->canHandleBlob(verifyBlobId)); 132 133 blobs::BlobMeta meta; 134 EXPECT_FALSE(handler->stat(verifyBlobId, &meta)); 135 } 136 137 TEST_F(FirmwareHandlerVerificationCompletedTest, 138 StatOnNormalBlobsReturnsSuccess) 139 { 140 getToVerificationCompleted(ActionStatus::success); 141 142 std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId}; 143 for (const auto& blob : testBlobs) 144 { 145 ASSERT_TRUE(handler->canHandleBlob(blob)); 146 147 blobs::BlobMeta meta = {}; 148 EXPECT_TRUE(handler->stat(blob, &meta)); 149 EXPECT_EQ(expectedIdleMeta, meta); 150 } 151 } 152 153 /* 154 * stat(session) - the verify blobid is open in this state, so stat on that once 155 * completed should have no effect. 156 */ 157 TEST_F(FirmwareHandlerVerificationCompletedTest, 158 SessionStatOnVerifyAfterSuccessDoesNothing) 159 { 160 /* Every time you stat() once it's triggered, it checks the state again 161 * until it's completed. 162 */ 163 getToVerificationCompleted(ActionStatus::success); 164 EXPECT_CALL(*verifyMockPtr, status()).Times(0); 165 166 blobs::BlobMeta meta, expectedMeta = {}; 167 expectedMeta.size = 0; 168 expectedMeta.blobState = flags | blobs::StateFlags::committed; 169 expectedMeta.metadata.push_back( 170 static_cast<std::uint8_t>(ActionStatus::success)); 171 172 EXPECT_TRUE(handler->stat(session, &meta)); 173 EXPECT_EQ(expectedMeta, meta); 174 expectedState(FirmwareBlobHandler::UpdateState::verificationCompleted); 175 } 176 177 TEST_F(FirmwareHandlerVerificationCompletedTest, 178 SessionStatOnVerifyAfterFailureDoesNothing) 179 { 180 getToVerificationCompleted(ActionStatus::failed); 181 EXPECT_CALL(*verifyMockPtr, status()).Times(0); 182 183 blobs::BlobMeta meta, expectedMeta = {}; 184 expectedMeta.size = 0; 185 expectedMeta.blobState = flags | blobs::StateFlags::commit_error; 186 expectedMeta.metadata.push_back( 187 static_cast<std::uint8_t>(ActionStatus::failed)); 188 189 EXPECT_TRUE(handler->stat(session, &meta)); 190 EXPECT_EQ(expectedMeta, meta); 191 expectedState(FirmwareBlobHandler::UpdateState::verificationCompleted); 192 } 193 194 /* 195 * open(blob) - all open should fail 196 */ 197 TEST_F(FirmwareHandlerVerificationCompletedTest, 198 OpeningAnyBlobAvailableFailsAfterSuccess) 199 { 200 getToVerificationCompleted(ActionStatus::success); 201 202 auto blobs = handler->getBlobIds(); 203 for (const auto& blob : blobs) 204 { 205 EXPECT_FALSE(handler->open(session + 1, flags, blob)); 206 } 207 } 208 209 TEST_F(FirmwareHandlerVerificationCompletedTest, 210 OpeningAnyBlobAvailableFailsAfterFailure) 211 { 212 getToVerificationCompleted(ActionStatus::failed); 213 214 auto blobs = handler->getBlobIds(); 215 for (const auto& blob : blobs) 216 { 217 EXPECT_FALSE(handler->open(session + 1, flags, blob)); 218 } 219 } 220 221 /* 222 * writemeta(session) - write meta should fail. 223 */ 224 TEST_F(FirmwareHandlerVerificationCompletedTest, 225 WriteMetaToVerifyBlobReturnsFailure) 226 { 227 getToVerificationCompleted(ActionStatus::success); 228 229 std::vector<std::uint8_t> bytes = {0x01, 0x02}; 230 EXPECT_FALSE(handler->writeMeta(session, 0, bytes)); 231 } 232 233 /* 234 * write(session) - write should fail. 235 */ 236 TEST_F(FirmwareHandlerVerificationCompletedTest, 237 WriteToVerifyBlobReturnsFailure) 238 { 239 getToVerificationCompleted(ActionStatus::success); 240 241 std::vector<std::uint8_t> bytes = {0x01, 0x02}; 242 EXPECT_FALSE(handler->write(session, 0, bytes)); 243 } 244 245 /* 246 * read(session) - read returns empty. 247 */ 248 TEST_F(FirmwareHandlerVerificationCompletedTest, ReadOfVerifyBlobReturnsEmpty) 249 { 250 getToVerificationCompleted(ActionStatus::success); 251 EXPECT_THAT(handler->read(session, 0, 1), IsEmpty()); 252 } 253 254 /* 255 * commit(session) - returns failure 256 */ 257 TEST_F(FirmwareHandlerVerificationCompletedTest, 258 CommitOnVerifyBlobAfterSuccessReturnsFailure) 259 { 260 /* If you've started this'll return success, but if it's finished, it won't 261 * let you try-again. 262 */ 263 getToVerificationCompleted(ActionStatus::success); 264 EXPECT_CALL(*verifyMockPtr, trigger()).Times(0); 265 266 EXPECT_FALSE(handler->commit(session, {})); 267 } 268 269 TEST_F(FirmwareHandlerVerificationCompletedTest, 270 CommitOnVerifyBlobAfterFailureReturnsFailure) 271 { 272 getToVerificationCompleted(ActionStatus::failed); 273 EXPECT_CALL(*verifyMockPtr, trigger()).Times(0); 274 275 EXPECT_FALSE(handler->commit(session, {})); 276 } 277 278 /* 279 * close(session) - close on the verify blobid: 280 * 1. if successful adds update blob id, changes state to UpdatePending 281 */ 282 TEST_F(FirmwareHandlerVerificationCompletedTest, 283 CloseAfterSuccessChangesStateAddsUpdateBlob) 284 { 285 getToVerificationCompleted(ActionStatus::success); 286 ASSERT_FALSE(handler->canHandleBlob(updateBlobId)); 287 288 handler->close(session); 289 EXPECT_TRUE(handler->canHandleBlob(updateBlobId)); 290 expectedState(FirmwareBlobHandler::UpdateState::updatePending); 291 } 292 293 /* 294 * close(session) - close on the verify blobid: 295 * 2. if unsuccessful it aborts. 296 */ 297 TEST_F(FirmwareHandlerVerificationCompletedTest, CloseAfterFailureAborts) 298 { 299 getToVerificationCompleted(ActionStatus::failed); 300 ASSERT_FALSE(handler->canHandleBlob(updateBlobId)); 301 302 handler->close(session); 303 ASSERT_FALSE(handler->canHandleBlob(updateBlobId)); 304 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 305 EXPECT_THAT(handler->getBlobIds(), 306 UnorderedElementsAreArray(startingBlobs)); 307 } 308 309 /* 310 * expire(session) 311 */ 312 TEST_F(FirmwareHandlerVerificationCompletedTest, 313 ExpireAfterVerificationCompletedAborts) 314 { 315 getToVerificationCompleted(ActionStatus::failed); 316 317 ASSERT_TRUE(handler->expire(session)); 318 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 319 EXPECT_THAT(handler->getBlobIds(), 320 UnorderedElementsAreArray(startingBlobs)); 321 } 322 323 } // namespace 324 } // namespace ipmi_flash 325