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:
SetUp()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
expectedState(FirmwareBlobHandler::UpdateState state)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
TEST_F(IpmiOnlyTwoFirmwaresTest,OpeningBiosAfterBlobFails)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
TEST_F(IpmiOnlyTwoFirmwaresTest,OpeningHashBeforeBiosSucceeds)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