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