1 /** 2 * The goal of these tests is to verify the behavior of all blob commands given 3 * the current state is uploadInProgress. This state is achieved when an image 4 * or hash blob is opened and the handler is expected to receive bytes. 5 */ 6 #include "firmware_handler.hpp" 7 #include "firmware_unittest.hpp" 8 #include "util.hpp" 9 10 #include <cstdint> 11 #include <string> 12 #include <vector> 13 14 #include <gtest/gtest.h> 15 16 namespace ipmi_flash 17 { 18 namespace 19 { 20 21 using ::testing::ContainerEq; 22 using ::testing::IsEmpty; 23 using ::testing::Return; 24 using ::testing::UnorderedElementsAreArray; 25 26 /* 27 * There are the following calls (parameters may vary): 28 * canHandleBlob(blob) 29 * getBlobIds 30 * deleteBlob(blob) 31 * stat(blob) 32 * stat(session) 33 * open(blob) 34 * close(session) 35 * writemeta(session) 36 * write(session) 37 * read(session) 38 * commit(session) 39 * 40 * Testing canHandleBlob is uninteresting in this state. Getting the BlobIDs 41 * will inform what canHandleBlob will return. 42 */ 43 class FirmwareHandlerUploadInProgressTest : public IpmiOnlyFirmwareStaticTest 44 {}; 45 46 TEST_F(FirmwareHandlerUploadInProgressTest, GetBlobIdsVerifyOutputActiveImage) 47 { 48 /* Opening the image file will add the active image blob id */ 49 openToInProgress(staticLayoutBlobId); 50 51 EXPECT_THAT(handler->getBlobIds(), 52 UnorderedElementsAreArray( 53 {staticLayoutBlobId, hashBlobId, activeImageBlobId})); 54 } 55 56 TEST_F(FirmwareHandlerUploadInProgressTest, GetBlobIdsVerifyOutputActiveHash) 57 { 58 /* Opening the image file will add the active image blob id */ 59 openToInProgress(hashBlobId); 60 61 EXPECT_THAT(handler->getBlobIds(), 62 UnorderedElementsAreArray( 63 {staticLayoutBlobId, hashBlobId, activeHashBlobId})); 64 } 65 66 /* 67 * stat(blob) 68 */ 69 TEST_F(FirmwareHandlerUploadInProgressTest, StatOnActiveImageReturnsFailure) 70 { 71 /* you cannot call stat() on the active image or the active hash or the 72 * verify blob. 73 */ 74 openToInProgress(staticLayoutBlobId); 75 ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId)); 76 77 blobs::BlobMeta meta; 78 EXPECT_FALSE(handler->stat(activeImageBlobId, &meta)); 79 } 80 81 TEST_F(FirmwareHandlerUploadInProgressTest, StatOnActiveHashReturnsFailure) 82 { 83 /* this test is separate from the active image one so that the state doesn't 84 * change from close. 85 */ 86 openToInProgress(hashBlobId); 87 ASSERT_TRUE(handler->canHandleBlob(activeHashBlobId)); 88 89 blobs::BlobMeta meta; 90 EXPECT_FALSE(handler->stat(activeHashBlobId, &meta)); 91 } 92 93 TEST_F(FirmwareHandlerUploadInProgressTest, StatOnNormalBlobsReturnsSuccess) 94 { 95 /* Calling stat() on the normal blobs (not the active) ones will work and 96 * return the same information as in the notYetStarted state. 97 */ 98 openToInProgress(staticLayoutBlobId); 99 100 std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId}; 101 for (const auto& blob : testBlobs) 102 { 103 blobs::BlobMeta meta = {}; 104 EXPECT_TRUE(handler->stat(blob, &meta)); 105 EXPECT_EQ(expectedIdleMeta, meta); 106 } 107 } 108 109 /* 110 * stat(session) 111 */ 112 TEST_F(FirmwareHandlerUploadInProgressTest, 113 CallingStatOnActiveImageOrHashSessionReturnsDetails) 114 { 115 /* This test will verify that the underlying image handler is called with 116 * this stat, in addition to the normal information. 117 */ 118 openToInProgress(staticLayoutBlobId); 119 120 EXPECT_CALL(*imageMock2, getSize()).WillOnce(Return(32)); 121 122 blobs::BlobMeta meta, expectedMeta = {}; 123 expectedMeta.size = 32; 124 expectedMeta.blobState = 125 static_cast<std::uint16_t>(blobs::OpenFlags::write) | 126 FirmwareFlags::UpdateFlags::ipmi; 127 EXPECT_TRUE(handler->stat(session, &meta)); 128 EXPECT_EQ(expectedMeta, meta); 129 } 130 131 /* 132 * open(blob) - While any blob is open, all other fail. 133 * 134 * The fullBlobsList is all the blob_ids present if both /flash/image and 135 * /flash/hash are opened, and one is left open (so there's no verify blob). if 136 * left closed, we'd be in verificationPending, not uploadInProgress. 137 */ 138 const std::vector<std::string> fullBlobsList = { 139 activeHashBlobId, activeImageBlobId, hashBlobId, staticLayoutBlobId}; 140 141 TEST_F(FirmwareHandlerUploadInProgressTest, OpeningHashFileWhileImageOpenFails) 142 { 143 /* To be in this state, something must be open (and specifically either an 144 * active image (or tarball) or the hash file. Also verifies you can't just 145 * re-open the currently open file. 146 */ 147 openToInProgress(staticLayoutBlobId); 148 149 for (const auto& blob : fullBlobsList) 150 { 151 EXPECT_FALSE(handler->open(2, flags, blob)); 152 } 153 } 154 155 TEST_F(FirmwareHandlerUploadInProgressTest, OpeningImageFileWhileHashOpenFails) 156 { 157 openToInProgress(hashBlobId); 158 159 for (const auto& blob : fullBlobsList) 160 { 161 EXPECT_FALSE(handler->open(2, flags, blob)); 162 } 163 } 164 165 /* 166 * close(session) - closing the hash or image will trigger a state transition to 167 * verificationPending. 168 * 169 * NOTE: Re-opening /flash/image will transition back to uploadInProgress, but 170 * that is verified in the verificationPending::open tests. 171 */ 172 TEST_F(FirmwareHandlerUploadInProgressTest, 173 ClosingImageFileTransitionsToVerificationPending) 174 { 175 EXPECT_FALSE(handler->canHandleBlob(verifyBlobId)); 176 openToInProgress(staticLayoutBlobId); 177 178 handler->close(session); 179 expectedState(FirmwareBlobHandler::UpdateState::verificationPending); 180 181 EXPECT_TRUE(handler->canHandleBlob(verifyBlobId)); 182 } 183 184 TEST_F(FirmwareHandlerUploadInProgressTest, 185 ClosingHashFileTransitionsToVerificationPending) 186 { 187 EXPECT_FALSE(handler->canHandleBlob(verifyBlobId)); 188 openToInProgress(hashBlobId); 189 190 handler->close(session); 191 expectedState(FirmwareBlobHandler::UpdateState::verificationPending); 192 193 EXPECT_FALSE(handler->canHandleBlob(verifyBlobId)); 194 } 195 196 /* 197 * writemeta(session) 198 */ 199 TEST_F(FirmwareHandlerUploadInProgressTest, 200 WriteMetaAgainstImageReturnsFailureIfNoDataHandler) 201 { 202 /* Calling write/read/writeMeta are uninteresting against the open blob in 203 * this case because the blob will just pass the call along. Whereas 204 * calling against the verify or update blob may be more interesting. 205 */ 206 openToInProgress(staticLayoutBlobId); 207 208 /* TODO: Consider adding a test that has a data handler, but that test 209 * already exists under the general writeMeta test suite. 210 */ 211 /* Note: with IPMI as the transport there's no data handler, so this should 212 * fail nicely. */ 213 std::vector<std::uint8_t> bytes = {0x01, 0x02}; 214 EXPECT_FALSE(handler->writeMeta(session, 0, bytes)); 215 } 216 217 /* 218 * write(session) 219 */ 220 TEST_F(FirmwareHandlerUploadInProgressTest, WriteToImageReturnsSuccess) 221 { 222 openToInProgress(staticLayoutBlobId); 223 std::vector<std::uint8_t> bytes = {0x01, 0x02}; 224 EXPECT_CALL(*imageMock2, write(0, ContainerEq(bytes))) 225 .WillOnce(Return(true)); 226 EXPECT_TRUE(handler->write(session, 0, bytes)); 227 } 228 229 TEST_F(FirmwareHandlerUploadInProgressTest, WriteToHashReturnsSuccess) 230 { 231 openToInProgress(hashBlobId); 232 std::vector<std::uint8_t> bytes = {0x01, 0x02}; 233 EXPECT_CALL(*hashImageMock, write(0, ContainerEq(bytes))) 234 .WillOnce(Return(true)); 235 EXPECT_TRUE(handler->write(session, 0, bytes)); 236 } 237 238 /* 239 * read(session) 240 */ 241 TEST_F(FirmwareHandlerUploadInProgressTest, ReadImageFileReturnsFailure) 242 { 243 /* Read is not supported. */ 244 openToInProgress(staticLayoutBlobId); 245 EXPECT_THAT(handler->read(session, 0, 32), IsEmpty()); 246 } 247 248 /* 249 * commit(session) 250 */ 251 TEST_F(FirmwareHandlerUploadInProgressTest, 252 CommitAgainstImageFileReturnsFailure) 253 { 254 /* Commit is only valid against specific blobs. */ 255 openToInProgress(staticLayoutBlobId); 256 EXPECT_FALSE(handler->commit(session, {})); 257 } 258 259 TEST_F(FirmwareHandlerUploadInProgressTest, CommitAgainstHashFileReturnsFailure) 260 { 261 openToInProgress(hashBlobId); 262 EXPECT_FALSE(handler->commit(session, {})); 263 } 264 265 /* 266 * deleteBlob(blob) 267 */ 268 TEST_F(FirmwareHandlerUploadInProgressTest, DeleteBlobReturnsFalse) 269 { 270 /* Try deleting all blobs, it doesn't really matter which though because you 271 * cannot close out an open session, therefore you must fail to delete 272 * anything unless everything is closed. 273 */ 274 openToInProgress(staticLayoutBlobId); 275 auto blobs = handler->getBlobIds(); 276 for (const auto& b : blobs) 277 { 278 EXPECT_FALSE(handler->deleteBlob(b)); 279 } 280 } 281 282 /* 283 * expire(session) 284 */ 285 TEST_F(FirmwareHandlerUploadInProgressTest, ExpireAbortsProcess) 286 { 287 openToInProgress(staticLayoutBlobId); 288 289 ASSERT_TRUE(handler->expire(session)); 290 EXPECT_THAT(handler->getBlobIds(), 291 UnorderedElementsAreArray(startingBlobs)); 292 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 293 } 294 295 } // namespace 296 } // namespace ipmi_flash 297