1 /**
2  * The goal of these tests is to verify the behavior of all blob commands given
3  * the current state is verificationPending.  This state is achieved as a
4  * transition out of uploadInProgress.
5  */
6 #include "firmware_handler.hpp"
7 #include "firmware_unittest.hpp"
8 #include "status.hpp"
9 #include "util.hpp"
10 
11 #include <algorithm>
12 #include <cstdint>
13 #include <string>
14 #include <vector>
15 
16 #include <gtest/gtest.h>
17 
18 namespace ipmi_flash
19 {
20 namespace
21 {
22 
23 using ::testing::IsEmpty;
24 using ::testing::Return;
25 using ::testing::UnorderedElementsAreArray;
26 
27 /*
28  * There are the following calls (parameters may vary):
29  * canHandleBlob(blob)
30  * getBlobIds
31  * deleteBlob(blob)
32  * stat(blob)
33  * stat(session)
34  * open(blob)
35  * close(session)
36  * writemeta(session)
37  * write(session)
38  * read(session)
39  * commit(session)
40  *
41  * Testing canHandleBlob is uninteresting in this state.  Getting the BlobIDs
42  * will inform what canHandleBlob will return.
43  */
44 
45 class FirmwareHandlerVerificationPendingTest : public IpmiOnlyFirmwareStaticTest
46 {};
47 
48 /*
49  * getBlobIds
50  */
TEST_F(FirmwareHandlerVerificationPendingTest,VerifyBlobIdAvailableInState)51 TEST_F(FirmwareHandlerVerificationPendingTest, VerifyBlobIdAvailableInState)
52 {
53     /* Only in the verificationPending state (and later), should the
54      * verifyBlobId be present.
55      */
56     EXPECT_FALSE(handler->canHandleBlob(verifyBlobId));
57 
58     getToVerificationPending(staticLayoutBlobId);
59 
60     EXPECT_TRUE(handler->canHandleBlob(verifyBlobId));
61     EXPECT_TRUE(handler->canHandleBlob(activeImageBlobId));
62     EXPECT_FALSE(handler->canHandleBlob(updateBlobId));
63 }
64 
65 /*
66  * delete(blob)
67  */
TEST_F(FirmwareHandlerVerificationPendingTest,DeleteVerifyPendingAbortsProcess)68 TEST_F(FirmwareHandlerVerificationPendingTest, DeleteVerifyPendingAbortsProcess)
69 {
70     /* It doesn't matter what blob id is used to delete in the design, so just
71      * delete the verify blob id
72      */
73     getToVerificationPending(staticLayoutBlobId);
74 
75     EXPECT_CALL(*verifyMockPtr, abort()).Times(0);
76 
77     ASSERT_TRUE(handler->canHandleBlob(verifyBlobId));
78     EXPECT_TRUE(handler->deleteBlob(verifyBlobId));
79 
80     std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId};
81     EXPECT_THAT(handler->getBlobIds(),
82                 UnorderedElementsAreArray(expectedBlobs));
83     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
84 }
85 
TEST_F(FirmwareHandlerVerificationPendingTest,DeleteActiveImageAbortsProcess)86 TEST_F(FirmwareHandlerVerificationPendingTest, DeleteActiveImageAbortsProcess)
87 {
88     getToVerificationPending(staticLayoutBlobId);
89 
90     EXPECT_CALL(*verifyMockPtr, abort()).Times(0);
91 
92     ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));
93     EXPECT_TRUE(handler->deleteBlob(activeImageBlobId));
94 
95     std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId};
96     EXPECT_THAT(handler->getBlobIds(),
97                 UnorderedElementsAreArray(expectedBlobs));
98     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
99 }
100 
TEST_F(FirmwareHandlerVerificationPendingTest,DeleteStaticLayoutAbortsProcess)101 TEST_F(FirmwareHandlerVerificationPendingTest, DeleteStaticLayoutAbortsProcess)
102 {
103     getToVerificationPending(staticLayoutBlobId);
104 
105     EXPECT_CALL(*verifyMockPtr, abort()).Times(0);
106 
107     ASSERT_TRUE(handler->canHandleBlob(staticLayoutBlobId));
108     EXPECT_TRUE(handler->deleteBlob(staticLayoutBlobId));
109 
110     std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId};
111     EXPECT_THAT(handler->getBlobIds(),
112                 UnorderedElementsAreArray(expectedBlobs));
113     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
114 }
115 
TEST_F(FirmwareHandlerVerificationPendingTest,DeleteHashAbortsProcess)116 TEST_F(FirmwareHandlerVerificationPendingTest, DeleteHashAbortsProcess)
117 {
118     getToVerificationPending(staticLayoutBlobId);
119 
120     EXPECT_CALL(*verifyMockPtr, abort()).Times(0);
121 
122     ASSERT_TRUE(handler->canHandleBlob(hashBlobId));
123     EXPECT_TRUE(handler->deleteBlob(hashBlobId));
124 
125     std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId};
126     EXPECT_THAT(handler->getBlobIds(),
127                 UnorderedElementsAreArray(expectedBlobs));
128     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
129 }
130 
131 /*
132  * expire(session)
133  */
TEST_F(FirmwareHandlerVerificationPendingTest,ExpireVerificationPendingAbortsProcess)134 TEST_F(FirmwareHandlerVerificationPendingTest,
135        ExpireVerificationPendingAbortsProcess)
136 {
137     getToVerificationPending(staticLayoutBlobId);
138 
139     EXPECT_CALL(*verifyMockPtr, abort()).Times(0);
140 
141     EXPECT_TRUE(handler->expire(session));
142 
143     std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId};
144     EXPECT_THAT(handler->getBlobIds(),
145                 UnorderedElementsAreArray(expectedBlobs));
146     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
147 }
148 
149 /*
150  * stat(blob)
151  */
TEST_F(FirmwareHandlerVerificationPendingTest,StatOnActiveImageReturnsFailure)152 TEST_F(FirmwareHandlerVerificationPendingTest, StatOnActiveImageReturnsFailure)
153 {
154     getToVerificationPending(staticLayoutBlobId);
155     ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));
156 
157     blobs::BlobMeta meta;
158     EXPECT_FALSE(handler->stat(activeImageBlobId, &meta));
159 }
160 
TEST_F(FirmwareHandlerVerificationPendingTest,StatOnActiveHashReturnsFailure)161 TEST_F(FirmwareHandlerVerificationPendingTest, StatOnActiveHashReturnsFailure)
162 {
163     getToVerificationPending(hashBlobId);
164     ASSERT_TRUE(handler->canHandleBlob(activeHashBlobId));
165 
166     blobs::BlobMeta meta;
167     EXPECT_FALSE(handler->stat(activeHashBlobId, &meta));
168 }
169 
TEST_F(FirmwareHandlerVerificationPendingTest,StatOnVerificationBlobReturnsFailure)170 TEST_F(FirmwareHandlerVerificationPendingTest,
171        StatOnVerificationBlobReturnsFailure)
172 {
173     getToVerificationPending(staticLayoutBlobId);
174     ASSERT_TRUE(handler->canHandleBlob(verifyBlobId));
175 
176     blobs::BlobMeta meta;
177     EXPECT_FALSE(handler->stat(verifyBlobId, &meta));
178 }
179 
TEST_F(FirmwareHandlerVerificationPendingTest,VerificationBlobNotFoundWithoutStaticDataAsWell)180 TEST_F(FirmwareHandlerVerificationPendingTest,
181        VerificationBlobNotFoundWithoutStaticDataAsWell)
182 {
183     /* If you only ever open the hash blob id, and never the firmware blob id,
184      * the verify blob isn't added.
185      */
186     getToVerificationPending(hashBlobId);
187     EXPECT_FALSE(handler->canHandleBlob(verifyBlobId));
188 }
189 
TEST_F(FirmwareHandlerVerificationPendingTest,StatOnNormalBlobsReturnsSuccess)190 TEST_F(FirmwareHandlerVerificationPendingTest, StatOnNormalBlobsReturnsSuccess)
191 {
192     getToVerificationPending(staticLayoutBlobId);
193 
194     std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId};
195     for (const auto& blob : testBlobs)
196     {
197         ASSERT_TRUE(handler->canHandleBlob(blob));
198         blobs::BlobMeta meta = {};
199         EXPECT_TRUE(handler->stat(blob, &meta));
200         EXPECT_EQ(expectedIdleMeta, meta);
201     }
202 }
203 
204 /*
205  * open(blob)
206  */
TEST_F(FirmwareHandlerVerificationPendingTest,OpenVerifyBlobSucceeds)207 TEST_F(FirmwareHandlerVerificationPendingTest, OpenVerifyBlobSucceeds)
208 {
209     getToVerificationPending(staticLayoutBlobId);
210 
211     /* the session is safe because it was already closed to get to this state.
212      */
213     EXPECT_TRUE(handler->open(session, flags, verifyBlobId));
214 }
215 
TEST_F(FirmwareHandlerVerificationPendingTest,OpenActiveBlobsFail)216 TEST_F(FirmwareHandlerVerificationPendingTest, OpenActiveBlobsFail)
217 {
218     /* Try opening the active blob Id.  This test is equivalent to trying to
219      * open the active hash blob id, in that neither are ever allowed.
220      */
221     getToVerificationPending(staticLayoutBlobId);
222     EXPECT_FALSE(handler->open(session, flags, activeImageBlobId));
223     EXPECT_FALSE(handler->open(session, flags, activeHashBlobId));
224 }
225 
TEST_F(FirmwareHandlerVerificationPendingTest,OpenImageBlobTransitionsToUploadInProgress)226 TEST_F(FirmwareHandlerVerificationPendingTest,
227        OpenImageBlobTransitionsToUploadInProgress)
228 {
229     getToVerificationPending(staticLayoutBlobId);
230 
231     /* Verify the active blob for the image is in the list once to start.
232      * Note: This is truly tested under the notYetStarted::open() test.
233      */
234     std::vector<std::string> expectedBlobs = {staticLayoutBlobId, hashBlobId,
235                                               verifyBlobId, activeImageBlobId};
236 
237     EXPECT_THAT(handler->getBlobIds(),
238                 UnorderedElementsAreArray(expectedBlobs));
239 
240     /* Verifies it isn't triggered again. */
241     EXPECT_CALL(*prepareMockPtr, trigger()).Times(0);
242 
243     EXPECT_CALL(*imageMock2, open(staticLayoutBlobId, std::ios::out))
244         .WillOnce(Return(true));
245     EXPECT_TRUE(handler->open(session, flags, staticLayoutBlobId));
246     expectedState(FirmwareBlobHandler::UpdateState::uploadInProgress);
247 
248     expectedBlobs.erase(
249         std::remove(expectedBlobs.begin(), expectedBlobs.end(), verifyBlobId),
250         expectedBlobs.end());
251 
252     /* Verify the active blob ID was not added to the list twice and
253      * verifyBlobId is removed
254      */
255     EXPECT_THAT(handler->getBlobIds(),
256                 UnorderedElementsAreArray(expectedBlobs));
257 }
258 
259 /*
260  * close(session)
261  */
TEST_F(FirmwareHandlerVerificationPendingTest,ClosingVerifyBlobWithoutCommitDoesNotChangeState)262 TEST_F(FirmwareHandlerVerificationPendingTest,
263        ClosingVerifyBlobWithoutCommitDoesNotChangeState)
264 {
265     /* commit() will change the state, closing post-commit is part of
266      * verificationStarted testing.
267      */
268     getToVerificationPending(staticLayoutBlobId);
269     EXPECT_TRUE(handler->open(session, flags, verifyBlobId));
270     expectedState(FirmwareBlobHandler::UpdateState::verificationPending);
271 
272     handler->close(session);
273     expectedState(FirmwareBlobHandler::UpdateState::verificationPending);
274 }
275 
276 /*
277  * commit(session)
278  */
TEST_F(FirmwareHandlerVerificationPendingTest,CommitOnVerifyBlobTriggersVerificationAndStateTransition)279 TEST_F(FirmwareHandlerVerificationPendingTest,
280        CommitOnVerifyBlobTriggersVerificationAndStateTransition)
281 {
282     getToVerificationPending(staticLayoutBlobId);
283     EXPECT_TRUE(handler->open(session, flags, verifyBlobId));
284     EXPECT_CALL(*verifyMockPtr, trigger()).WillOnce(Return(true));
285 
286     EXPECT_TRUE(handler->commit(session, {}));
287     expectedState(FirmwareBlobHandler::UpdateState::verificationStarted);
288 }
289 
290 /*
291  * stat(session) - in this state, you can only open(verifyBlobId) without
292  * changing state.
293  */
TEST_F(FirmwareHandlerVerificationPendingTest,StatOnVerifyBlobIdReturnsState)294 TEST_F(FirmwareHandlerVerificationPendingTest, StatOnVerifyBlobIdReturnsState)
295 {
296     /* If this is called before commit(), it's still verificationPending, so it
297      * just returns the state is other
298      */
299     getToVerificationPending(staticLayoutBlobId);
300     EXPECT_TRUE(handler->open(session, flags, verifyBlobId));
301     EXPECT_CALL(*verifyMockPtr, trigger()).Times(0);
302     EXPECT_CALL(*verifyMockPtr, status()).Times(0);
303 
304     blobs::BlobMeta meta, expectedMeta = {};
305     expectedMeta.size = 0;
306     expectedMeta.blobState = flags;
307     expectedMeta.metadata.push_back(
308         static_cast<std::uint8_t>(ActionStatus::unknown));
309 
310     EXPECT_TRUE(handler->stat(session, &meta));
311     EXPECT_EQ(expectedMeta, meta);
312 }
313 
314 /*
315  * writemeta(session)
316  */
TEST_F(FirmwareHandlerVerificationPendingTest,WriteMetaAgainstVerifyFails)317 TEST_F(FirmwareHandlerVerificationPendingTest, WriteMetaAgainstVerifyFails)
318 {
319     /* The verifyBlobId has no data handler, which means write meta fails. */
320     getToVerificationPending(staticLayoutBlobId);
321 
322     EXPECT_TRUE(handler->open(session, flags, verifyBlobId));
323 
324     std::vector<std::uint8_t> bytes = {0x01, 0x02};
325     EXPECT_FALSE(handler->writeMeta(session, 0, bytes));
326 }
327 
328 /*
329  * write(session)
330  */
TEST_F(FirmwareHandlerVerificationPendingTest,WriteAgainstVerifyBlobIdFails)331 TEST_F(FirmwareHandlerVerificationPendingTest, WriteAgainstVerifyBlobIdFails)
332 {
333     getToVerificationPending(staticLayoutBlobId);
334 
335     EXPECT_TRUE(handler->open(session, flags, verifyBlobId));
336 
337     std::vector<std::uint8_t> bytes = {0x01, 0x02};
338     EXPECT_FALSE(handler->write(session, 0, bytes));
339 }
340 
341 /*
342  * read(session)
343  */
TEST_F(FirmwareHandlerVerificationPendingTest,ReadAgainstVerifyBlobIdReturnsEmpty)344 TEST_F(FirmwareHandlerVerificationPendingTest,
345        ReadAgainstVerifyBlobIdReturnsEmpty)
346 {
347     getToVerificationPending(staticLayoutBlobId);
348 
349     EXPECT_TRUE(handler->open(session, flags, verifyBlobId));
350     EXPECT_THAT(handler->read(session, 0, 1), IsEmpty());
351 }
352 
353 } // namespace
354 } // namespace ipmi_flash
355