1 /* The goal of these tests is to verify that once a host-client has started the 2 * process with one blob bundle, they cannot pivot to upload data to another. 3 * 4 * This prevent someone from starting to upload a BMC firmware, and then midway 5 * through start uploading a BIOS image. 6 */ 7 #include "firmware_handler.hpp" 8 #include "flags.hpp" 9 #include "image_mock.hpp" 10 #include "status.hpp" 11 #include "triggerable_mock.hpp" 12 #include "util.hpp" 13 14 #include <memory> 15 #include <string> 16 #include <unordered_map> 17 #include <vector> 18 19 #include <gtest/gtest.h> 20 21 namespace ipmi_flash 22 { 23 namespace 24 { 25 26 using ::testing::Return; 27 28 class IpmiOnlyTwoFirmwaresTest : public ::testing::Test 29 { 30 protected: 31 void SetUp() override 32 { 33 std::unique_ptr<ImageHandlerInterface> image = 34 std::make_unique<ImageHandlerMock>(); 35 hashImageMock = reinterpret_cast<ImageHandlerMock*>(image.get()); 36 blobs.emplace_back(hashBlobId, std::move(image)); 37 38 image = std::make_unique<ImageHandlerMock>(); 39 staticImageMock = reinterpret_cast<ImageHandlerMock*>(image.get()); 40 blobs.emplace_back(staticLayoutBlobId, std::move(image)); 41 42 image = std::make_unique<ImageHandlerMock>(); 43 biosImageMock = reinterpret_cast<ImageHandlerMock*>(image.get()); 44 blobs.emplace_back(biosBlobId, std::move(image)); 45 46 std::unique_ptr<TriggerableActionInterface> bmcPrepareMock = 47 std::make_unique<TriggerMock>(); 48 bmcPrepareMockPtr = 49 reinterpret_cast<TriggerMock*>(bmcPrepareMock.get()); 50 51 std::unique_ptr<TriggerableActionInterface> bmcVerifyMock = 52 std::make_unique<TriggerMock>(); 53 bmcVerifyMockPtr = reinterpret_cast<TriggerMock*>(bmcVerifyMock.get()); 54 55 std::unique_ptr<TriggerableActionInterface> bmcUpdateMock = 56 std::make_unique<TriggerMock>(); 57 bmcUpdateMockPtr = reinterpret_cast<TriggerMock*>(bmcUpdateMock.get()); 58 59 std::unique_ptr<TriggerableActionInterface> biosPrepareMock = 60 std::make_unique<TriggerMock>(); 61 biosPrepareMockPtr = 62 reinterpret_cast<TriggerMock*>(biosPrepareMock.get()); 63 64 std::unique_ptr<TriggerableActionInterface> biosVerifyMock = 65 std::make_unique<TriggerMock>(); 66 biosVerifyMockPtr = 67 reinterpret_cast<TriggerMock*>(biosVerifyMock.get()); 68 69 std::unique_ptr<TriggerableActionInterface> biosUpdateMock = 70 std::make_unique<TriggerMock>(); 71 biosUpdateMockPtr = 72 reinterpret_cast<TriggerMock*>(biosUpdateMock.get()); 73 74 ActionMap packs; 75 76 std::unique_ptr<ActionPack> bmcPack = std::make_unique<ActionPack>(); 77 bmcPack->preparation = std::move(bmcPrepareMock); 78 bmcPack->verification = std::move(bmcVerifyMock); 79 bmcPack->update = std::move(bmcUpdateMock); 80 81 std::unique_ptr<ActionPack> biosPack = std::make_unique<ActionPack>(); 82 biosPack->preparation = std::move(biosPrepareMock); 83 biosPack->verification = std::move(biosVerifyMock); 84 biosPack->update = std::move(biosUpdateMock); 85 86 packs[staticLayoutBlobId] = std::move(bmcPack); 87 packs[biosBlobId] = std::move(biosPack); 88 89 std::vector<DataHandlerPack> data; 90 data.emplace_back(FirmwareFlags::UpdateFlags::ipmi, nullptr); 91 92 handler = FirmwareBlobHandler::CreateFirmwareBlobHandler( 93 std::move(blobs), std::move(data), std::move(packs)); 94 } 95 96 void expectedState(FirmwareBlobHandler::UpdateState state) 97 { 98 auto realHandler = dynamic_cast<FirmwareBlobHandler*>(handler.get()); 99 EXPECT_EQ(state, realHandler->getCurrentState()); 100 } 101 102 ImageHandlerMock *hashImageMock, *staticImageMock, *biosImageMock; 103 104 std::vector<HandlerPack> blobs; 105 106 std::unique_ptr<blobs::GenericBlobInterface> handler; 107 108 TriggerMock *bmcPrepareMockPtr, *bmcVerifyMockPtr, *bmcUpdateMockPtr; 109 TriggerMock *biosPrepareMockPtr, *biosVerifyMockPtr, *biosUpdateMockPtr; 110 111 std::uint16_t session = 1; 112 std::uint16_t flags = static_cast<std::uint16_t>(blobs::OpenFlags::write) | 113 FirmwareFlags::UpdateFlags::ipmi; 114 }; 115 116 TEST_F(IpmiOnlyTwoFirmwaresTest, OpeningBiosAfterBlobFails) 117 { 118 /* You can only have one file open at a time, and the first firmware file 119 * you open locks it down 120 */ 121 EXPECT_CALL(*staticImageMock, open(staticLayoutBlobId, std::ios::out)) 122 .WillOnce(Return(true)); 123 EXPECT_CALL(*bmcPrepareMockPtr, trigger()).WillOnce(Return(true)); 124 125 EXPECT_TRUE(handler->open(session, flags, staticLayoutBlobId)); 126 expectedState(FirmwareBlobHandler::UpdateState::uploadInProgress); 127 128 EXPECT_CALL(*staticImageMock, close()).WillOnce(Return()); 129 handler->close(session); 130 131 expectedState(FirmwareBlobHandler::UpdateState::verificationPending); 132 133 EXPECT_CALL(*biosImageMock, open(biosBlobId, std::ios::out)).Times(0); 134 EXPECT_FALSE(handler->open(session, flags, biosBlobId)); 135 } 136 137 TEST_F(IpmiOnlyTwoFirmwaresTest, OpeningHashBeforeBiosSucceeds) 138 { 139 /* Opening the hash blob does nothing special in this regard. */ 140 EXPECT_CALL(*hashImageMock, open(hashBlobId, std::ios::out)) 141 .WillOnce(Return(true)); 142 EXPECT_TRUE(handler->open(session, flags, hashBlobId)); 143 144 expectedState(FirmwareBlobHandler::UpdateState::uploadInProgress); 145 146 EXPECT_CALL(*hashImageMock, close()).WillOnce(Return()); 147 handler->close(session); 148 149 expectedState(FirmwareBlobHandler::UpdateState::verificationPending); 150 ASSERT_FALSE(handler->canHandleBlob(verifyBlobId)); 151 152 EXPECT_CALL(*biosImageMock, open(biosBlobId, std::ios::out)) 153 .WillOnce(Return(true)); 154 EXPECT_TRUE(handler->open(session, flags, biosBlobId)); 155 156 expectedState(FirmwareBlobHandler::UpdateState::uploadInProgress); 157 158 EXPECT_CALL(*biosImageMock, close()).WillOnce(Return()); 159 handler->close(session); 160 } 161 162 } // namespace 163 } // namespace ipmi_flash 164