1 /* The goal of these tests is to verify the behavior of all blob commands given
2  * the current state is verificationStarted.  This state is achieved as a out of
3  * verificationPending.
4  */
5 #include "firmware_handler.hpp"
6 #include "firmware_unittest.hpp"
7 #include "status.hpp"
8 #include "util.hpp"
9 
10 #include <cstdint>
11 #include <string>
12 #include <vector>
13 
14 #include <gtest/gtest.h>
15 
16 namespace ipmi_flash
17 {
18 namespace
19 {
20 
21 using ::testing::IsEmpty;
22 using ::testing::Return;
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  * Testing canHandleBlob is uninteresting in this state.  Getting the BlobIDs
40  * will inform what canHandleBlob will return.
41  */
42 
43 class FirmwareHandlerVerificationStartedTest : public IpmiOnlyFirmwareStaticTest
44 {};
45 
46 /*
47  * canHandleBlob(blob)
48  * getBlobIds()
49  */
50 TEST_F(FirmwareHandlerVerificationStartedTest, GetBlobIdsReturnsExpectedList)
51 {
52     getToVerificationStarted(staticLayoutBlobId);
53 
54     auto blobs = handler->getBlobIds();
55     EXPECT_THAT(
56         blobs, UnorderedElementsAreArray({activeImageBlobId, staticLayoutBlobId,
57                                           hashBlobId, verifyBlobId}));
58 
59     for (const auto& blob : blobs)
60     {
61         EXPECT_TRUE(handler->canHandleBlob(blob));
62     }
63 }
64 
65 /*
66  * stat(session)
67  */
68 TEST_F(FirmwareHandlerVerificationStartedTest,
69        StatOnVerifyBlobIdAfterCommitChecksStateAndReturnsRunning)
70 {
71     getToVerificationStarted(staticLayoutBlobId);
72     EXPECT_CALL(*verifyMockPtr, status())
73         .WillOnce(Return(ActionStatus::running));
74 
75     blobs::BlobMeta meta, expectedMeta = {};
76     expectedMeta.size = 0;
77     expectedMeta.blobState = flags | blobs::StateFlags::committing;
78     expectedMeta.metadata.push_back(
79         static_cast<std::uint8_t>(ActionStatus::running));
80 
81     EXPECT_TRUE(handler->stat(session, &meta));
82     EXPECT_EQ(expectedMeta, meta);
83 }
84 
85 TEST_F(FirmwareHandlerVerificationStartedTest,
86        StatOnVerifyBlobIdAfterCommitChecksStateAndReturnsOther)
87 {
88     getToVerificationStarted(staticLayoutBlobId);
89     EXPECT_CALL(*verifyMockPtr, status())
90         .WillOnce(Return(ActionStatus::unknown));
91 
92     blobs::BlobMeta meta, expectedMeta = {};
93     expectedMeta.size = 0;
94     expectedMeta.blobState = flags | blobs::StateFlags::committing;
95     expectedMeta.metadata.push_back(
96         static_cast<std::uint8_t>(ActionStatus::unknown));
97 
98     EXPECT_TRUE(handler->stat(session, &meta));
99     EXPECT_EQ(expectedMeta, meta);
100 }
101 
102 TEST_F(FirmwareHandlerVerificationStartedTest,
103        StatOnVerifyBlobIdAfterCommitCheckStateAndReturnsFailed)
104 {
105     /* If the returned state from the verification handler is failed, it sets
106      * commit_error and transitions to verificationCompleted.
107      */
108     getToVerificationStarted(staticLayoutBlobId);
109     EXPECT_CALL(*verifyMockPtr, status())
110         .WillOnce(Return(ActionStatus::failed));
111 
112     blobs::BlobMeta meta, expectedMeta = {};
113     expectedMeta.size = 0;
114     expectedMeta.blobState = flags | blobs::StateFlags::commit_error;
115     expectedMeta.metadata.push_back(
116         static_cast<std::uint8_t>(ActionStatus::failed));
117 
118     EXPECT_TRUE(handler->stat(session, &meta));
119     EXPECT_EQ(expectedMeta, meta);
120     expectedState(FirmwareBlobHandler::UpdateState::verificationCompleted);
121 }
122 
123 TEST_F(FirmwareHandlerVerificationStartedTest,
124        StatOnVerifyBlobIdAfterCommitCheckStateAndReturnsSuccess)
125 {
126     /* If the returned state from the verification handler is success, it sets
127      * committed and transitions to verificationCompleted.
128      */
129     getToVerificationStarted(staticLayoutBlobId);
130     EXPECT_CALL(*verifyMockPtr, status())
131         .WillOnce(Return(ActionStatus::success));
132 
133     blobs::BlobMeta meta, expectedMeta = {};
134     expectedMeta.size = 0;
135     expectedMeta.blobState = flags | blobs::StateFlags::committed;
136     expectedMeta.metadata.push_back(
137         static_cast<std::uint8_t>(ActionStatus::success));
138 
139     EXPECT_TRUE(handler->stat(session, &meta));
140     EXPECT_EQ(expectedMeta, meta);
141     expectedState(FirmwareBlobHandler::UpdateState::verificationCompleted);
142 }
143 
144 /*
145  * deleteBlob(blob)
146  */
147 TEST_F(FirmwareHandlerVerificationStartedTest, DeleteBlobReturnsFalse)
148 {
149     /* Try deleting all blobs, it doesn't really matter which though because you
150      * cannot close out an open session, therefore you must fail to delete
151      * anything unless everything is closed.
152      */
153     getToVerificationStarted(staticLayoutBlobId);
154     auto blobs = handler->getBlobIds();
155     for (const auto& b : blobs)
156     {
157         EXPECT_FALSE(handler->deleteBlob(b));
158     }
159 }
160 
161 /*
162  * stat(blob)
163  */
164 TEST_F(FirmwareHandlerVerificationStartedTest, StatOnActiveImageReturnsFailure)
165 {
166     getToVerificationStarted(staticLayoutBlobId);
167     ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));
168 
169     blobs::BlobMeta meta;
170     EXPECT_FALSE(handler->stat(activeImageBlobId, &meta));
171 }
172 
173 TEST_F(FirmwareHandlerVerificationStartedTest, StatOnActiveHashReturnsFailure)
174 {
175     getToVerificationStartedWitHashBlob();
176     ASSERT_TRUE(handler->canHandleBlob(activeHashBlobId));
177 
178     blobs::BlobMeta meta;
179     EXPECT_FALSE(handler->stat(activeHashBlobId, &meta));
180 }
181 
182 TEST_F(FirmwareHandlerVerificationStartedTest, StatOnVerifyBlobReturnsFailure)
183 {
184     /* the verifyBlobId is available starting at verificationPending. */
185     getToVerificationStarted(staticLayoutBlobId);
186     ASSERT_TRUE(handler->canHandleBlob(verifyBlobId));
187 
188     blobs::BlobMeta meta;
189     EXPECT_FALSE(handler->stat(verifyBlobId, &meta));
190 }
191 
192 TEST_F(FirmwareHandlerVerificationStartedTest, StatOnNormalBlobsReturnsSuccess)
193 {
194     getToVerificationStarted(staticLayoutBlobId);
195 
196     std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId};
197     for (const auto& blob : testBlobs)
198     {
199         ASSERT_TRUE(handler->canHandleBlob(blob));
200 
201         blobs::BlobMeta meta = {};
202         EXPECT_TRUE(handler->stat(blob, &meta));
203         EXPECT_EQ(expectedIdleMeta, meta);
204     }
205 }
206 
207 /*
208  * writemeta(session)
209  */
210 TEST_F(FirmwareHandlerVerificationStartedTest,
211        WriteMetaOnVerifySessionReturnsFailure)
212 {
213     getToVerificationStarted(staticLayoutBlobId);
214 
215     std::vector<std::uint8_t> bytes = {0x01, 0x02};
216     EXPECT_FALSE(handler->writeMeta(session, 0, bytes));
217 }
218 
219 /*
220  * write(session)
221  */
222 TEST_F(FirmwareHandlerVerificationStartedTest,
223        WriteOnVerifySessionReturnsFailure)
224 {
225     getToVerificationStarted(staticLayoutBlobId);
226 
227     std::vector<std::uint8_t> bytes = {0x01, 0x02};
228     EXPECT_FALSE(handler->write(session, 0, bytes));
229 }
230 
231 /*
232  * open(blob) - there is nothing you can open, this state has an open file.
233  */
234 TEST_F(FirmwareHandlerVerificationStartedTest,
235        AttemptToOpenImageFileReturnsFailure)
236 {
237     /* Attempt to open a file one normally can open, however, as there is
238      * already a file open, this will fail.
239      */
240     getToVerificationStarted(staticLayoutBlobId);
241 
242     auto blobsToOpen = handler->getBlobIds();
243     for (const auto& blob : blobsToOpen)
244     {
245         EXPECT_FALSE(handler->open(session + 1, flags, blob));
246     }
247 }
248 
249 /*
250  * read(session)
251  */
252 TEST_F(FirmwareHandlerVerificationStartedTest, ReadOfVerifyBlobReturnsEmpty)
253 {
254     getToVerificationStarted(staticLayoutBlobId);
255     EXPECT_THAT(handler->read(session, 0, 1), IsEmpty());
256 }
257 
258 /*
259  * commit(session)
260  */
261 TEST_F(FirmwareHandlerVerificationStartedTest,
262        CommitOnVerifyDuringVerificationHasNoImpact)
263 {
264     getToVerificationStarted(staticLayoutBlobId);
265     EXPECT_TRUE(handler->commit(session, {}));
266     expectedState(FirmwareBlobHandler::UpdateState::verificationStarted);
267 }
268 
269 /*
270  * close(session) - close while state if verificationStarted without calling
271  * stat first will abort.
272  */
273 TEST_F(FirmwareHandlerVerificationStartedTest,
274        CloseOnVerifyDuringVerificationAbortsProcess)
275 {
276     getToVerificationStarted(staticLayoutBlobId);
277     EXPECT_CALL(*verifyMockPtr, abort()).Times(1);
278 
279     EXPECT_TRUE(handler->close(session));
280 
281     EXPECT_THAT(handler->getBlobIds(),
282                 UnorderedElementsAreArray(startingBlobs));
283 
284     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
285 }
286 
287 /*
288  * expire(session)
289  */
290 TEST_F(FirmwareHandlerVerificationStartedTest,
291        ExpireOnSessionDuringVerificationAbortsProcess)
292 {
293     getToVerificationStarted(staticLayoutBlobId);
294     EXPECT_CALL(*verifyMockPtr, abort()).Times(0);
295 
296     EXPECT_TRUE(handler->expire(session));
297 
298     EXPECT_THAT(handler->getBlobIds(),
299                 UnorderedElementsAreArray(startingBlobs));
300 
301     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
302 }
303 
304 } // namespace
305 } // namespace ipmi_flash
306