1 /* The goal of these tests is to verify the behavior of all blob commands given 2 * the current state is updatePending. This state is achieved as an exit from 3 * verificationCompleted. 4 */ 5 #include "firmware_handler.hpp" 6 #include "firmware_unittest.hpp" 7 #include "status.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::IsEmpty; 22 using ::testing::Return; 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 * Testing canHandleBlob is uninteresting in this state. Getting the BlobIDs 40 * will inform what canHandleBlob will return. 41 */ 42 43 class FirmwareHandlerUpdatePendingTest : public IpmiOnlyFirmwareStaticTest 44 {}; 45 46 /* 47 * There are the following calls (parameters may vary): 48 * canHandleBlob(blob) 49 * getBlobIds 50 */ 51 TEST_F(FirmwareHandlerUpdatePendingTest, GetBlobsListHasExpectedValues) 52 { 53 getToUpdatePending(); 54 55 EXPECT_THAT(handler->getBlobIds(), 56 UnorderedElementsAreArray({updateBlobId, activeImageBlobId, 57 hashBlobId, staticLayoutBlobId})); 58 } 59 60 /* 61 * open(blob) - because updatePending is in a fileOpen==false state, one can 62 * then open blobs. However, because we're in a special state, we will restrict 63 * them s.t. they can only open the updateBlobId. 64 */ 65 TEST_F(FirmwareHandlerUpdatePendingTest, 66 OpenUpdateBlobIdIsSuccessfulAndDoesNotChangeState) 67 { 68 getToUpdatePending(); 69 70 /* Opening the update blob isn't interesting, except it's required for 71 * commit() which triggers the update process. 72 */ 73 EXPECT_TRUE(handler->open(session, flags, updateBlobId)); 74 expectedState(FirmwareBlobHandler::UpdateState::updatePending); 75 } 76 77 TEST_F(FirmwareHandlerUpdatePendingTest, OpenAnyBlobOtherThanUpdateFails) 78 { 79 getToUpdatePending(); 80 81 auto blobs = handler->getBlobIds(); 82 for (const auto& blob : blobs) 83 { 84 if (blob == updateBlobId) 85 { 86 continue; 87 } 88 EXPECT_FALSE(handler->open(session, flags, blob)); 89 } 90 } 91 92 /* 93 * close(session) - close from this state is uninteresting. 94 */ 95 TEST_F(FirmwareHandlerUpdatePendingTest, CloseUpdateBlobDoesNotChangeState) 96 { 97 /* Verify nothing changes when one just opens, then closes the updateBlobId. 98 */ 99 getToUpdatePending(); 100 101 EXPECT_TRUE(handler->open(session, flags, updateBlobId)); 102 103 handler->close(session); 104 105 expectedState(FirmwareBlobHandler::UpdateState::updatePending); 106 EXPECT_TRUE(handler->canHandleBlob(updateBlobId)); 107 } 108 109 /* 110 * writemeta(session) - this will return failure. 111 */ 112 TEST_F(FirmwareHandlerUpdatePendingTest, WriteMetaToUpdateBlobReturnsFailure) 113 { 114 getToUpdatePending(); 115 116 EXPECT_TRUE(handler->open(session, flags, updateBlobId)); 117 EXPECT_FALSE(handler->writeMeta(session, 0, {0x01})); 118 } 119 120 /* 121 * write(session) 122 */ 123 TEST_F(FirmwareHandlerUpdatePendingTest, WriteToUpdateBlobReturnsFailure) 124 { 125 getToUpdatePending(); 126 127 EXPECT_TRUE(handler->open(session, flags, updateBlobId)); 128 EXPECT_FALSE(handler->write(session, 0, {0x01})); 129 } 130 131 /* 132 * read(session) 133 */ 134 TEST_F(FirmwareHandlerUpdatePendingTest, ReadFromUpdateBlobIdReturnsEmpty) 135 { 136 getToUpdatePending(); 137 EXPECT_THAT(handler->read(session, 0, 1), IsEmpty()); 138 } 139 140 /* 141 * stat(blob) 142 */ 143 TEST_F(FirmwareHandlerUpdatePendingTest, StatOnActiveImageReturnsFailure) 144 { 145 getToUpdatePending(); 146 ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId)); 147 148 blobs::BlobMeta meta; 149 EXPECT_FALSE(handler->stat(activeImageBlobId, &meta)); 150 } 151 152 TEST_F(FirmwareHandlerUpdatePendingTest, StatOnUpdateBlobReturnsFailure) 153 { 154 getToUpdatePending(); 155 ASSERT_TRUE(handler->canHandleBlob(updateBlobId)); 156 157 blobs::BlobMeta meta; 158 EXPECT_FALSE(handler->stat(updateBlobId, &meta)); 159 } 160 161 TEST_F(FirmwareHandlerUpdatePendingTest, StatOnNormalBlobsReturnsSuccess) 162 { 163 getToUpdatePending(); 164 165 for (const auto& blob : startingBlobs) 166 { 167 ASSERT_TRUE(handler->canHandleBlob(blob)); 168 169 blobs::BlobMeta meta = {}; 170 EXPECT_TRUE(handler->stat(blob, &meta)); 171 EXPECT_EQ(expectedIdleMeta, meta); 172 } 173 } 174 175 /* 176 * stat(session) 177 * In this case, you can open updateBlobId without changing state, therefore, 178 * let's call stat() against a session against this file. This done, ahead of 179 * commit() should report the state as "other." 180 */ 181 TEST_F(FirmwareHandlerUpdatePendingTest, 182 SessionStatOnUpdateBlobIdReturnsFailure) 183 { 184 getToUpdatePending(); 185 EXPECT_TRUE(handler->open(session, flags, updateBlobId)); 186 expectedState(FirmwareBlobHandler::UpdateState::updatePending); 187 188 blobs::BlobMeta meta, expectedMeta = {}; 189 expectedMeta.size = 0; 190 expectedMeta.blobState = flags; 191 expectedMeta.metadata.push_back( 192 static_cast<std::uint8_t>(ActionStatus::unknown)); 193 194 EXPECT_TRUE(handler->stat(session, &meta)); 195 EXPECT_EQ(expectedMeta, meta); 196 expectedState(FirmwareBlobHandler::UpdateState::updatePending); 197 } 198 199 /* 200 * commit(session) 201 */ 202 TEST_F(FirmwareHandlerUpdatePendingTest, 203 CommitOnUpdateBlobTriggersUpdateAndChangesState) 204 { 205 /* Commit triggers the update mechanism (similarly for the verifyBlobId) and 206 * changes state to updateStarted. 207 */ 208 getToUpdatePending(); 209 EXPECT_TRUE(handler->open(session, flags, updateBlobId)); 210 expectedState(FirmwareBlobHandler::UpdateState::updatePending); 211 212 EXPECT_CALL(*updateMockPtr, trigger()).WillOnce(Return(true)); 213 214 EXPECT_TRUE(handler->commit(session, {})); 215 expectedState(FirmwareBlobHandler::UpdateState::updateStarted); 216 } 217 218 TEST_F(FirmwareHandlerUpdatePendingTest, 219 CommitOnUpdateBlobTriggersUpdateAndReturnsFailureDoesNotChangeState) 220 { 221 getToUpdatePending(); 222 EXPECT_TRUE(handler->open(session, flags, updateBlobId)); 223 expectedState(FirmwareBlobHandler::UpdateState::updatePending); 224 225 EXPECT_CALL(*updateMockPtr, trigger()).WillOnce(Return(false)); 226 227 EXPECT_FALSE(handler->commit(session, {})); 228 expectedState(FirmwareBlobHandler::UpdateState::updatePending); 229 } 230 231 /* 232 * deleteBlob(blob) 233 */ 234 TEST_F(FirmwareHandlerUpdatePendingTest, DeleteUpdateAbortsProcess) 235 { 236 /* It doesn't matter what blob id is used to delete in the design, so just 237 * delete the update blob id 238 */ 239 getToUpdatePending(); 240 241 EXPECT_CALL(*updateMockPtr, abort()).Times(0); 242 243 ASSERT_TRUE(handler->canHandleBlob(updateBlobId)); 244 EXPECT_TRUE(handler->deleteBlob(updateBlobId)); 245 246 EXPECT_THAT(handler->getBlobIds(), 247 UnorderedElementsAreArray(startingBlobs)); 248 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 249 } 250 251 TEST_F(FirmwareHandlerUpdatePendingTest, DeleteActiveImageAbortsProcess) 252 { 253 getToUpdatePending(); 254 255 EXPECT_CALL(*updateMockPtr, abort()).Times(0); 256 257 ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId)); 258 EXPECT_TRUE(handler->deleteBlob(activeImageBlobId)); 259 260 EXPECT_THAT(handler->getBlobIds(), 261 UnorderedElementsAreArray(startingBlobs)); 262 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 263 } 264 265 TEST_F(FirmwareHandlerUpdatePendingTest, DeleteStaticLayoutAbortsProcess) 266 { 267 getToUpdatePending(); 268 269 EXPECT_CALL(*updateMockPtr, abort()).Times(0); 270 271 ASSERT_TRUE(handler->canHandleBlob(staticLayoutBlobId)); 272 EXPECT_TRUE(handler->deleteBlob(staticLayoutBlobId)); 273 274 EXPECT_THAT(handler->getBlobIds(), 275 UnorderedElementsAreArray(startingBlobs)); 276 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 277 } 278 279 TEST_F(FirmwareHandlerUpdatePendingTest, DeleteHashAbortsProcess) 280 { 281 getToUpdatePending(); 282 283 EXPECT_CALL(*updateMockPtr, abort()).Times(0); 284 285 ASSERT_TRUE(handler->canHandleBlob(hashBlobId)); 286 EXPECT_TRUE(handler->deleteBlob(hashBlobId)); 287 288 EXPECT_THAT(handler->getBlobIds(), 289 UnorderedElementsAreArray(startingBlobs)); 290 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 291 } 292 293 /* 294 * expire(session) 295 */ 296 TEST_F(FirmwareHandlerUpdatePendingTest, ExpireOnUpdatePendingAborstsProcess) 297 { 298 getToUpdatePending(); 299 300 EXPECT_CALL(*updateMockPtr, abort()).Times(0); 301 302 ASSERT_TRUE(handler->expire(session)); 303 EXPECT_THAT(handler->getBlobIds(), 304 UnorderedElementsAreArray(startingBlobs)); 305 expectedState(FirmwareBlobHandler::UpdateState::notYetStarted); 306 } 307 308 } // namespace 309 } // namespace ipmi_flash 310