1 /**
2  * The goal of these tests is to verify the behavior of all blob commands given
3  * the current state is verificationCompleted.  This state is achieved as a out
4  * of verificationStarted.
5  */
6 #include "firmware_handler.hpp"
7 #include "firmware_unittest.hpp"
8 #include "status.hpp"
9 #include "util.hpp"
10 
11 #include <cstdint>
12 #include <string>
13 #include <vector>
14 
15 #include <gtest/gtest.h>
16 
17 namespace ipmi_flash
18 {
19 namespace
20 {
21 
22 using ::testing::IsEmpty;
23 using ::testing::UnorderedElementsAreArray;
24 
25 /*
26  * There are the following calls (parameters may vary):
27  * canHandleBlob(blob)
28  * getBlobIds
29  * deleteBlob(blob)
30  * stat(blob)
31  * stat(session)
32  * open(blob)
33  * close(session)
34  * writemeta(session)
35  * write(session)
36  * read(session)
37  * commit(session)
38  *
39  * Like the state verificationStarted, there is a file open in
40  * verificationCompleted.  This state is transitioned to after a stat() command
41  * indicates a successful verification.
42  */
43 
44 class FirmwareHandlerVerificationCompletedTest :
45     public IpmiOnlyFirmwareStaticTest
46 {};
47 
48 /*
49  * deleteBlob(blob)
50  */
51 TEST_F(FirmwareHandlerVerificationCompletedTest, DeleteBlobReturnsFalse)
52 {
53     /* Try deleting all blobs, it doesn't really matter which though because you
54      * cannot close out an open session, therefore you must fail to delete
55      * anything unless everything is closed.
56      */
57     getToVerificationCompleted(ActionStatus::success);
58     auto blobs = handler->getBlobIds();
59     for (const auto& b : blobs)
60     {
61         EXPECT_FALSE(handler->deleteBlob(b));
62     }
63 }
64 
65 /*
66  * canHandleBlob
67  */
68 TEST_F(FirmwareHandlerVerificationCompletedTest,
69        OnVerificationCompleteSuccessUpdateBlobIdNotPresent)
70 {
71     /* the uploadBlobId is only added on close() of the verifyBlobId.  This is a
72      * consistent behavior with verifyBlobId only added when closing the image
73      * or hash.
74      */
75     getToVerificationCompleted(ActionStatus::success);
76     EXPECT_FALSE(handler->canHandleBlob(updateBlobId));
77 }
78 
79 TEST_F(FirmwareHandlerVerificationCompletedTest,
80        OnVerificationCompleteFailureUpdateBlobIdNotPresent)
81 {
82     getToVerificationCompleted(ActionStatus::failed);
83     EXPECT_FALSE(handler->canHandleBlob(updateBlobId));
84 }
85 
86 /*
87  * getBlobIds
88  */
89 TEST_F(FirmwareHandlerVerificationCompletedTest, GetBlobIdsReturnsExpectedList)
90 {
91     getToVerificationCompleted(ActionStatus::success);
92     EXPECT_THAT(
93         handler->getBlobIds(),
94         UnorderedElementsAreArray(
95             {verifyBlobId, hashBlobId, activeImageBlobId, staticLayoutBlobId}));
96 }
97 
98 /*
99  * stat(blob)
100  */
101 TEST_F(FirmwareHandlerVerificationCompletedTest,
102        StatOnActiveImageReturnsFailure)
103 {
104     getToVerificationCompleted(ActionStatus::success);
105     ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));
106 
107     blobs::BlobMeta meta;
108     EXPECT_FALSE(handler->stat(activeImageBlobId, &meta));
109 }
110 
111 TEST_F(FirmwareHandlerVerificationCompletedTest,
112        VerifyActiveHashIdMissingInThisCase)
113 {
114     /* The path taken to get to this state never opened the hash blob Id, which
115      * is fine.  But let's verify it behaved as intended.
116      */
117     getToVerificationCompleted(ActionStatus::success);
118     EXPECT_FALSE(handler->canHandleBlob(activeHashBlobId));
119 }
120 
121 /* TODO: Add sufficient warning that you can get to verificationCompleted
122  * without ever opening the image blob id (or the tarball one).
123  *
124  * Although in this case, it's expected that any verification triggered would
125  * certainly fail.  So, although it's possible, it's uninteresting.
126  */
127 
128 TEST_F(FirmwareHandlerVerificationCompletedTest, StatOnVerifyBlobReturnsFailure)
129 {
130     getToVerificationCompleted(ActionStatus::success);
131     ASSERT_TRUE(handler->canHandleBlob(verifyBlobId));
132 
133     blobs::BlobMeta meta;
134     EXPECT_FALSE(handler->stat(verifyBlobId, &meta));
135 }
136 
137 TEST_F(FirmwareHandlerVerificationCompletedTest,
138        StatOnNormalBlobsReturnsSuccess)
139 {
140     getToVerificationCompleted(ActionStatus::success);
141 
142     std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId};
143     for (const auto& blob : testBlobs)
144     {
145         ASSERT_TRUE(handler->canHandleBlob(blob));
146 
147         blobs::BlobMeta meta = {};
148         EXPECT_TRUE(handler->stat(blob, &meta));
149         EXPECT_EQ(expectedIdleMeta, meta);
150     }
151 }
152 
153 /*
154  * stat(session) - the verify blobid is open in this state, so stat on that once
155  * completed should have no effect.
156  */
157 TEST_F(FirmwareHandlerVerificationCompletedTest,
158        SessionStatOnVerifyAfterSuccessDoesNothing)
159 {
160     /* Every time you stat() once it's triggered, it checks the state again
161      * until it's completed.
162      */
163     getToVerificationCompleted(ActionStatus::success);
164     EXPECT_CALL(*verifyMockPtr, status()).Times(0);
165 
166     blobs::BlobMeta meta, expectedMeta = {};
167     expectedMeta.size = 0;
168     expectedMeta.blobState = flags | blobs::StateFlags::committed;
169     expectedMeta.metadata.push_back(
170         static_cast<std::uint8_t>(ActionStatus::success));
171 
172     EXPECT_TRUE(handler->stat(session, &meta));
173     EXPECT_EQ(expectedMeta, meta);
174     expectedState(FirmwareBlobHandler::UpdateState::verificationCompleted);
175 }
176 
177 TEST_F(FirmwareHandlerVerificationCompletedTest,
178        SessionStatOnVerifyAfterFailureDoesNothing)
179 {
180     getToVerificationCompleted(ActionStatus::failed);
181     EXPECT_CALL(*verifyMockPtr, status()).Times(0);
182 
183     blobs::BlobMeta meta, expectedMeta = {};
184     expectedMeta.size = 0;
185     expectedMeta.blobState = flags | blobs::StateFlags::commit_error;
186     expectedMeta.metadata.push_back(
187         static_cast<std::uint8_t>(ActionStatus::failed));
188 
189     EXPECT_TRUE(handler->stat(session, &meta));
190     EXPECT_EQ(expectedMeta, meta);
191     expectedState(FirmwareBlobHandler::UpdateState::verificationCompleted);
192 }
193 
194 /*
195  * open(blob) - all open should fail
196  */
197 TEST_F(FirmwareHandlerVerificationCompletedTest,
198        OpeningAnyBlobAvailableFailsAfterSuccess)
199 {
200     getToVerificationCompleted(ActionStatus::success);
201 
202     auto blobs = handler->getBlobIds();
203     for (const auto& blob : blobs)
204     {
205         EXPECT_FALSE(handler->open(session + 1, flags, blob));
206     }
207 }
208 
209 TEST_F(FirmwareHandlerVerificationCompletedTest,
210        OpeningAnyBlobAvailableFailsAfterFailure)
211 {
212     getToVerificationCompleted(ActionStatus::failed);
213 
214     auto blobs = handler->getBlobIds();
215     for (const auto& blob : blobs)
216     {
217         EXPECT_FALSE(handler->open(session + 1, flags, blob));
218     }
219 }
220 
221 /*
222  * writemeta(session) - write meta should fail.
223  */
224 TEST_F(FirmwareHandlerVerificationCompletedTest,
225        WriteMetaToVerifyBlobReturnsFailure)
226 {
227     getToVerificationCompleted(ActionStatus::success);
228 
229     std::vector<std::uint8_t> bytes = {0x01, 0x02};
230     EXPECT_FALSE(handler->writeMeta(session, 0, bytes));
231 }
232 
233 /*
234  * write(session) - write should fail.
235  */
236 TEST_F(FirmwareHandlerVerificationCompletedTest,
237        WriteToVerifyBlobReturnsFailure)
238 {
239     getToVerificationCompleted(ActionStatus::success);
240 
241     std::vector<std::uint8_t> bytes = {0x01, 0x02};
242     EXPECT_FALSE(handler->write(session, 0, bytes));
243 }
244 
245 /*
246  * read(session) - read returns empty.
247  */
248 TEST_F(FirmwareHandlerVerificationCompletedTest, ReadOfVerifyBlobReturnsEmpty)
249 {
250     getToVerificationCompleted(ActionStatus::success);
251     EXPECT_THAT(handler->read(session, 0, 1), IsEmpty());
252 }
253 
254 /*
255  * commit(session) - returns failure
256  */
257 TEST_F(FirmwareHandlerVerificationCompletedTest,
258        CommitOnVerifyBlobAfterSuccessReturnsFailure)
259 {
260     /* If you've started this'll return success, but if it's finished, it won't
261      * let you try-again.
262      */
263     getToVerificationCompleted(ActionStatus::success);
264     EXPECT_CALL(*verifyMockPtr, trigger()).Times(0);
265 
266     EXPECT_FALSE(handler->commit(session, {}));
267 }
268 
269 TEST_F(FirmwareHandlerVerificationCompletedTest,
270        CommitOnVerifyBlobAfterFailureReturnsFailure)
271 {
272     getToVerificationCompleted(ActionStatus::failed);
273     EXPECT_CALL(*verifyMockPtr, trigger()).Times(0);
274 
275     EXPECT_FALSE(handler->commit(session, {}));
276 }
277 
278 /*
279  * close(session) - close on the verify blobid:
280  *   1. if successful adds update blob id, changes state to UpdatePending
281  */
282 TEST_F(FirmwareHandlerVerificationCompletedTest,
283        CloseAfterSuccessChangesStateAddsUpdateBlob)
284 {
285     getToVerificationCompleted(ActionStatus::success);
286     ASSERT_FALSE(handler->canHandleBlob(updateBlobId));
287 
288     handler->close(session);
289     EXPECT_TRUE(handler->canHandleBlob(updateBlobId));
290     expectedState(FirmwareBlobHandler::UpdateState::updatePending);
291 }
292 
293 /*
294  * close(session) - close on the verify blobid:
295  *   2. if unsuccessful it aborts.
296  */
297 TEST_F(FirmwareHandlerVerificationCompletedTest, CloseAfterFailureAborts)
298 {
299     getToVerificationCompleted(ActionStatus::failed);
300     ASSERT_FALSE(handler->canHandleBlob(updateBlobId));
301 
302     handler->close(session);
303     ASSERT_FALSE(handler->canHandleBlob(updateBlobId));
304     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
305     EXPECT_THAT(handler->getBlobIds(),
306                 UnorderedElementsAreArray(startingBlobs));
307 }
308 
309 /*
310  * expire(session)
311  */
312 TEST_F(FirmwareHandlerVerificationCompletedTest,
313        ExpireAfterVerificationCompletedAborts)
314 {
315     getToVerificationCompleted(ActionStatus::failed);
316 
317     ASSERT_TRUE(handler->expire(session));
318     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
319     EXPECT_THAT(handler->getBlobIds(),
320                 UnorderedElementsAreArray(startingBlobs));
321 }
322 
323 } // namespace
324 } // namespace ipmi_flash
325