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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,DeleteBlobReturnsFalse)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,OnVerificationCompleteSuccessUpdateBlobIdNotPresent)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
TEST_F(FirmwareHandlerVerificationCompletedTest,OnVerificationCompleteFailureUpdateBlobIdNotPresent)79 TEST_F(FirmwareHandlerVerificationCompletedTest,
80 OnVerificationCompleteFailureUpdateBlobIdNotPresent)
81 {
82 getToVerificationCompleted(ActionStatus::failed);
83 EXPECT_FALSE(handler->canHandleBlob(updateBlobId));
84 }
85
86 /*
87 * getBlobIds
88 */
TEST_F(FirmwareHandlerVerificationCompletedTest,GetBlobIdsReturnsExpectedList)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,StatOnActiveImageReturnsFailure)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
TEST_F(FirmwareHandlerVerificationCompletedTest,VerifyActiveHashIdMissingInThisCase)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
TEST_F(FirmwareHandlerVerificationCompletedTest,StatOnVerifyBlobReturnsFailure)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
TEST_F(FirmwareHandlerVerificationCompletedTest,StatOnNormalBlobsReturnsSuccess)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,SessionStatOnVerifyAfterSuccessDoesNothing)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
TEST_F(FirmwareHandlerVerificationCompletedTest,SessionStatOnVerifyAfterFailureDoesNothing)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,OpeningAnyBlobAvailableFailsAfterSuccess)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
TEST_F(FirmwareHandlerVerificationCompletedTest,OpeningAnyBlobAvailableFailsAfterFailure)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,WriteMetaToVerifyBlobReturnsFailure)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,WriteToVerifyBlobReturnsFailure)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,ReadOfVerifyBlobReturnsEmpty)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,CommitOnVerifyBlobAfterSuccessReturnsFailure)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
TEST_F(FirmwareHandlerVerificationCompletedTest,CommitOnVerifyBlobAfterFailureReturnsFailure)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,CloseAfterSuccessChangesStateAddsUpdateBlob)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,CloseAfterFailureAborts)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 */
TEST_F(FirmwareHandlerVerificationCompletedTest,ExpireAfterVerificationCompletedAborts)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