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 updateStarted.  This state is achieved as an exit from
3*ded66d0fSJason Ling  * updatePending.
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 
40*ded66d0fSJason Ling class FirmwareHandlerUpdateStartedTest : public IpmiOnlyFirmwareStaticTest
41*ded66d0fSJason Ling {};
42*ded66d0fSJason Ling 
43*ded66d0fSJason Ling /*
44*ded66d0fSJason Ling  * open(blob)
45*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,AttemptToOpenFilesReturnsFailure)46*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, AttemptToOpenFilesReturnsFailure)
47*ded66d0fSJason Ling {
48*ded66d0fSJason Ling     /* In state updateStarted a file is open, which means no others can be. */
49*ded66d0fSJason Ling     getToUpdateStarted();
50*ded66d0fSJason Ling 
51*ded66d0fSJason Ling     auto blobsToOpen = handler->getBlobIds();
52*ded66d0fSJason Ling     for (const auto& blob : blobsToOpen)
53*ded66d0fSJason Ling     {
54*ded66d0fSJason Ling         EXPECT_FALSE(handler->open(session + 1, flags, blob));
55*ded66d0fSJason Ling     }
56*ded66d0fSJason Ling }
57*ded66d0fSJason Ling 
58*ded66d0fSJason Ling /* canHandleBlob(blob)
59*ded66d0fSJason Ling  * getBlobIds
60*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,VerifyListOfBlobs)61*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, VerifyListOfBlobs)
62*ded66d0fSJason Ling {
63*ded66d0fSJason Ling     getToUpdateStarted();
64*ded66d0fSJason Ling 
65*ded66d0fSJason Ling     EXPECT_THAT(
66*ded66d0fSJason Ling         handler->getBlobIds(),
67*ded66d0fSJason Ling         UnorderedElementsAreArray(
68*ded66d0fSJason Ling             {updateBlobId, hashBlobId, activeImageBlobId, staticLayoutBlobId}));
69*ded66d0fSJason Ling }
70*ded66d0fSJason Ling 
71*ded66d0fSJason Ling /*
72*ded66d0fSJason Ling  * deleteBlob(blob)
73*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,DeleteBlobReturnsFalse)74*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, DeleteBlobReturnsFalse)
75*ded66d0fSJason Ling {
76*ded66d0fSJason Ling     /* Try deleting all blobs, it doesn't really matter which though because you
77*ded66d0fSJason Ling      * cannot close out an open session, therefore you must fail to delete
78*ded66d0fSJason Ling      * anything unless everything is closed.
79*ded66d0fSJason Ling      */
80*ded66d0fSJason Ling     getToUpdateStarted();
81*ded66d0fSJason Ling     auto blobs = handler->getBlobIds();
82*ded66d0fSJason Ling     for (const auto& b : blobs)
83*ded66d0fSJason Ling     {
84*ded66d0fSJason Ling         EXPECT_FALSE(handler->deleteBlob(b));
85*ded66d0fSJason Ling     }
86*ded66d0fSJason Ling }
87*ded66d0fSJason Ling 
88*ded66d0fSJason Ling /*
89*ded66d0fSJason Ling  * stat(blob)
90*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,StatOnActiveImageReturnsFailure)91*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, StatOnActiveImageReturnsFailure)
92*ded66d0fSJason Ling {
93*ded66d0fSJason Ling     getToUpdateStarted();
94*ded66d0fSJason Ling 
95*ded66d0fSJason Ling     ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));
96*ded66d0fSJason Ling 
97*ded66d0fSJason Ling     blobs::BlobMeta meta;
98*ded66d0fSJason Ling     EXPECT_FALSE(handler->stat(activeImageBlobId, &meta));
99*ded66d0fSJason Ling }
100*ded66d0fSJason Ling 
TEST_F(FirmwareHandlerUpdateStartedTest,StatOnUpdateBlobReturnsFailure)101*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, StatOnUpdateBlobReturnsFailure)
102*ded66d0fSJason Ling {
103*ded66d0fSJason Ling     getToUpdateStarted();
104*ded66d0fSJason Ling 
105*ded66d0fSJason Ling     ASSERT_TRUE(handler->canHandleBlob(updateBlobId));
106*ded66d0fSJason Ling 
107*ded66d0fSJason Ling     blobs::BlobMeta meta;
108*ded66d0fSJason Ling     EXPECT_FALSE(handler->stat(updateBlobId, &meta));
109*ded66d0fSJason Ling }
110*ded66d0fSJason Ling 
TEST_F(FirmwareHandlerUpdateStartedTest,StatOnNormalBlobsReturnsSuccess)111*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, StatOnNormalBlobsReturnsSuccess)
112*ded66d0fSJason Ling {
113*ded66d0fSJason Ling     getToUpdateStarted();
114*ded66d0fSJason Ling 
115*ded66d0fSJason Ling     std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId};
116*ded66d0fSJason Ling     for (const auto& blob : testBlobs)
117*ded66d0fSJason Ling     {
118*ded66d0fSJason Ling         ASSERT_TRUE(handler->canHandleBlob(blob));
119*ded66d0fSJason Ling 
120*ded66d0fSJason Ling         blobs::BlobMeta meta = {};
121*ded66d0fSJason Ling         EXPECT_TRUE(handler->stat(blob, &meta));
122*ded66d0fSJason Ling         EXPECT_EQ(expectedIdleMeta, meta);
123*ded66d0fSJason Ling     }
124*ded66d0fSJason Ling }
125*ded66d0fSJason Ling 
126*ded66d0fSJason Ling /*
127*ded66d0fSJason Ling  * writemeta(session)
128*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,WriteMetaToUpdateBlobReturnsFailure)129*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, WriteMetaToUpdateBlobReturnsFailure)
130*ded66d0fSJason Ling {
131*ded66d0fSJason Ling     getToUpdateStarted();
132*ded66d0fSJason Ling     EXPECT_FALSE(handler->writeMeta(session, 0, {0x01}));
133*ded66d0fSJason Ling }
134*ded66d0fSJason Ling 
135*ded66d0fSJason Ling /*
136*ded66d0fSJason Ling  * write(session)
137*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,WriteToUpdateBlobReturnsFailure)138*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, WriteToUpdateBlobReturnsFailure)
139*ded66d0fSJason Ling {
140*ded66d0fSJason Ling     getToUpdateStarted();
141*ded66d0fSJason Ling     EXPECT_FALSE(handler->write(session, 0, {0x01}));
142*ded66d0fSJason Ling }
143*ded66d0fSJason Ling 
144*ded66d0fSJason Ling /*
145*ded66d0fSJason Ling  * read(session)
146*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,ReadFromUpdateBlobReturnsEmpty)147*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, ReadFromUpdateBlobReturnsEmpty)
148*ded66d0fSJason Ling {
149*ded66d0fSJason Ling     getToUpdateStarted();
150*ded66d0fSJason Ling     EXPECT_THAT(handler->read(session, 0, 1), IsEmpty());
151*ded66d0fSJason Ling }
152*ded66d0fSJason Ling 
153*ded66d0fSJason Ling /*
154*ded66d0fSJason Ling  * commit(session)
155*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,CallingCommitShouldReturnTrueAndHaveNoEffect)156*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest,
157*ded66d0fSJason Ling        CallingCommitShouldReturnTrueAndHaveNoEffect)
158*ded66d0fSJason Ling {
159*ded66d0fSJason Ling     getToUpdateStarted();
160*ded66d0fSJason Ling     EXPECT_CALL(*updateMockPtr, trigger()).Times(0);
161*ded66d0fSJason Ling 
162*ded66d0fSJason Ling     EXPECT_TRUE(handler->commit(session, {}));
163*ded66d0fSJason Ling     expectedState(FirmwareBlobHandler::UpdateState::updateStarted);
164*ded66d0fSJason Ling }
165*ded66d0fSJason Ling 
166*ded66d0fSJason Ling /*
167*ded66d0fSJason Ling  * stat(session) - this will trigger a check, and the state may change.
168*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,CallStatChecksActionStatusReturnsRunningDoesNotChangeState)169*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest,
170*ded66d0fSJason Ling        CallStatChecksActionStatusReturnsRunningDoesNotChangeState)
171*ded66d0fSJason Ling {
172*ded66d0fSJason Ling     getToUpdateStarted();
173*ded66d0fSJason Ling     EXPECT_CALL(*updateMockPtr, status())
174*ded66d0fSJason Ling         .WillOnce(Return(ActionStatus::running));
175*ded66d0fSJason Ling 
176*ded66d0fSJason Ling     blobs::BlobMeta meta, expectedMeta = {};
177*ded66d0fSJason Ling     expectedMeta.size = 0;
178*ded66d0fSJason Ling     expectedMeta.blobState = flags | blobs::StateFlags::committing;
179*ded66d0fSJason Ling     expectedMeta.metadata.push_back(
180*ded66d0fSJason Ling         static_cast<std::uint8_t>(ActionStatus::running));
181*ded66d0fSJason Ling 
182*ded66d0fSJason Ling     EXPECT_TRUE(handler->stat(session, &meta));
183*ded66d0fSJason Ling     EXPECT_EQ(expectedMeta, meta);
184*ded66d0fSJason Ling     expectedState(FirmwareBlobHandler::UpdateState::updateStarted);
185*ded66d0fSJason Ling }
186*ded66d0fSJason Ling 
TEST_F(FirmwareHandlerUpdateStartedTest,CallStatChecksActionStatusReturnsFailedChangesStateToCompleted)187*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest,
188*ded66d0fSJason Ling        CallStatChecksActionStatusReturnsFailedChangesStateToCompleted)
189*ded66d0fSJason Ling {
190*ded66d0fSJason Ling     getToUpdateStarted();
191*ded66d0fSJason Ling     EXPECT_CALL(*updateMockPtr, status())
192*ded66d0fSJason Ling         .WillOnce(Return(ActionStatus::failed));
193*ded66d0fSJason Ling 
194*ded66d0fSJason Ling     blobs::BlobMeta meta, expectedMeta = {};
195*ded66d0fSJason Ling     expectedMeta.size = 0;
196*ded66d0fSJason Ling     expectedMeta.blobState = flags | blobs::StateFlags::commit_error;
197*ded66d0fSJason Ling     expectedMeta.metadata.push_back(
198*ded66d0fSJason Ling         static_cast<std::uint8_t>(ActionStatus::failed));
199*ded66d0fSJason Ling 
200*ded66d0fSJason Ling     EXPECT_TRUE(handler->stat(session, &meta));
201*ded66d0fSJason Ling     EXPECT_EQ(expectedMeta, meta);
202*ded66d0fSJason Ling     expectedState(FirmwareBlobHandler::UpdateState::updateCompleted);
203*ded66d0fSJason Ling }
204*ded66d0fSJason Ling 
TEST_F(FirmwareHandlerUpdateStartedTest,CallStatChecksActionStatusReturnsSuccessChangesStateToCompleted)205*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest,
206*ded66d0fSJason Ling        CallStatChecksActionStatusReturnsSuccessChangesStateToCompleted)
207*ded66d0fSJason Ling {
208*ded66d0fSJason Ling     getToUpdateStarted();
209*ded66d0fSJason Ling     EXPECT_CALL(*updateMockPtr, status())
210*ded66d0fSJason Ling         .WillOnce(Return(ActionStatus::success));
211*ded66d0fSJason Ling 
212*ded66d0fSJason Ling     blobs::BlobMeta meta, expectedMeta = {};
213*ded66d0fSJason Ling     expectedMeta.size = 0;
214*ded66d0fSJason Ling     expectedMeta.blobState = flags | blobs::StateFlags::committed;
215*ded66d0fSJason Ling     expectedMeta.metadata.push_back(
216*ded66d0fSJason Ling         static_cast<std::uint8_t>(ActionStatus::success));
217*ded66d0fSJason Ling 
218*ded66d0fSJason Ling     EXPECT_TRUE(handler->stat(session, &meta));
219*ded66d0fSJason Ling     EXPECT_EQ(expectedMeta, meta);
220*ded66d0fSJason Ling     expectedState(FirmwareBlobHandler::UpdateState::updateCompleted);
221*ded66d0fSJason Ling }
222*ded66d0fSJason Ling 
223*ded66d0fSJason Ling /*
224*ded66d0fSJason Ling  * close(session) - this will abort.
225*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,CloseOnUpdateDuringUpdateAbortsProcess)226*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest, CloseOnUpdateDuringUpdateAbortsProcess)
227*ded66d0fSJason Ling {
228*ded66d0fSJason Ling     getToUpdateStarted();
229*ded66d0fSJason Ling     EXPECT_CALL(*updateMockPtr, abort()).Times(1);
230*ded66d0fSJason Ling 
231*ded66d0fSJason Ling     EXPECT_TRUE(handler->close(session));
232*ded66d0fSJason Ling 
233*ded66d0fSJason Ling     EXPECT_THAT(handler->getBlobIds(),
234*ded66d0fSJason Ling                 UnorderedElementsAreArray(startingBlobs));
235*ded66d0fSJason Ling 
236*ded66d0fSJason Ling     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
237*ded66d0fSJason Ling }
238*ded66d0fSJason Ling 
239*ded66d0fSJason Ling /*
240*ded66d0fSJason Ling  * expire(session)
241*ded66d0fSJason Ling  */
TEST_F(FirmwareHandlerUpdateStartedTest,ExpireOnUpdateDuringUpdateAbortsProcess)242*ded66d0fSJason Ling TEST_F(FirmwareHandlerUpdateStartedTest,
243*ded66d0fSJason Ling        ExpireOnUpdateDuringUpdateAbortsProcess)
244*ded66d0fSJason Ling {
245*ded66d0fSJason Ling     getToUpdateStarted();
246*ded66d0fSJason Ling     EXPECT_CALL(*updateMockPtr, abort()).Times(0);
247*ded66d0fSJason Ling 
248*ded66d0fSJason Ling     ASSERT_TRUE(handler->expire(session));
249*ded66d0fSJason Ling 
250*ded66d0fSJason Ling     EXPECT_THAT(handler->getBlobIds(),
251*ded66d0fSJason Ling                 UnorderedElementsAreArray(startingBlobs));
252*ded66d0fSJason Ling 
253*ded66d0fSJason Ling     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
254*ded66d0fSJason Ling }
255*ded66d0fSJason Ling 
256*ded66d0fSJason Ling } // namespace
257*ded66d0fSJason Ling } // namespace ipmi_flash
258