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