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