1 /* The goal of these tests is to verify the behavior of all blob commands given
2  * the current state is UpdateCompleted.  This state is achieved as an exit from
3  * updateStarted.
4  *
5  * This can be reached with success or failure from an update, and is reached
6  * via a stat() call from updatedStarted.
7  */
8 #include "firmware_handler.hpp"
9 #include "firmware_unittest.hpp"
10 #include "status.hpp"
11 #include "util.hpp"
12 
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::UnorderedElementsAreArray;
25 
26 /*
27  * There are the following calls (parameters may vary):
28  * canHandleBlob(blob)
29  * getBlobIds
30  * deleteBlob(blob)
31  * stat(blob)
32  * stat(session)
33  * open(blob)
34  * close(session)
35  * writemeta(session)
36  * write(session)
37  * read(session)
38  * commit(session)
39  */
40 
41 class FirmwareHandlerUpdateCompletedTest : public IpmiOnlyFirmwareStaticTest
42 {};
43 
44 /*
45  * open(blob)
46  */
TEST_F(FirmwareHandlerUpdateCompletedTest,AttemptToOpenFilesReturnsFailureAfterSuccess)47 TEST_F(FirmwareHandlerUpdateCompletedTest,
48        AttemptToOpenFilesReturnsFailureAfterSuccess)
49 {
50     /* In state updateCompleted a file is open, which means no others can be. */
51     getToUpdateCompleted(ActionStatus::success);
52 
53     auto blobsToOpen = handler->getBlobIds();
54     for (const auto& blob : blobsToOpen)
55     {
56         EXPECT_FALSE(handler->open(session + 1, flags, blob));
57     }
58 }
59 
60 /*
61  * stat(session)
62  */
TEST_F(FirmwareHandlerUpdateCompletedTest,CallingStatSessionAfterCompletedSuccessReturnsStateWithoutRechecking)63 TEST_F(FirmwareHandlerUpdateCompletedTest,
64        CallingStatSessionAfterCompletedSuccessReturnsStateWithoutRechecking)
65 {
66     getToUpdateCompleted(ActionStatus::success);
67     EXPECT_CALL(*updateMockPtr, status()).Times(0);
68 
69     blobs::BlobMeta meta, expectedMeta = {};
70     expectedMeta.size = 0;
71     expectedMeta.blobState = flags | blobs::StateFlags::committed;
72     expectedMeta.metadata.push_back(
73         static_cast<std::uint8_t>(ActionStatus::success));
74 
75     EXPECT_TRUE(handler->stat(session, &meta));
76     EXPECT_EQ(expectedMeta, meta);
77     expectedState(FirmwareBlobHandler::UpdateState::updateCompleted);
78 }
79 
TEST_F(FirmwareHandlerUpdateCompletedTest,CallingStatSessionAfterCompletedFailureReturnsStateWithoutRechecking)80 TEST_F(FirmwareHandlerUpdateCompletedTest,
81        CallingStatSessionAfterCompletedFailureReturnsStateWithoutRechecking)
82 {
83     getToUpdateCompleted(ActionStatus::failed);
84     EXPECT_CALL(*updateMockPtr, status()).Times(0);
85 
86     blobs::BlobMeta meta, expectedMeta = {};
87     expectedMeta.size = 0;
88     expectedMeta.blobState = flags | blobs::StateFlags::commit_error;
89     expectedMeta.metadata.push_back(
90         static_cast<std::uint8_t>(ActionStatus::failed));
91 
92     EXPECT_TRUE(handler->stat(session, &meta));
93     EXPECT_EQ(expectedMeta, meta);
94     expectedState(FirmwareBlobHandler::UpdateState::updateCompleted);
95 }
96 
97 /*
98  * stat(blob)
99  */
TEST_F(FirmwareHandlerUpdateCompletedTest,StatOnActiveImageReturnsFailure)100 TEST_F(FirmwareHandlerUpdateCompletedTest, StatOnActiveImageReturnsFailure)
101 {
102     getToUpdateCompleted(ActionStatus::success);
103 
104     ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));
105 
106     blobs::BlobMeta meta;
107     EXPECT_FALSE(handler->stat(activeImageBlobId, &meta));
108 }
109 
TEST_F(FirmwareHandlerUpdateCompletedTest,StatOnUpdateBlobReturnsFailure)110 TEST_F(FirmwareHandlerUpdateCompletedTest, StatOnUpdateBlobReturnsFailure)
111 {
112     getToUpdateCompleted(ActionStatus::success);
113 
114     ASSERT_TRUE(handler->canHandleBlob(updateBlobId));
115 
116     blobs::BlobMeta meta;
117     EXPECT_FALSE(handler->stat(updateBlobId, &meta));
118 }
119 
TEST_F(FirmwareHandlerUpdateCompletedTest,StatOnNormalBlobsReturnsSuccess)120 TEST_F(FirmwareHandlerUpdateCompletedTest, StatOnNormalBlobsReturnsSuccess)
121 {
122     getToUpdateCompleted(ActionStatus::success);
123 
124     std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId};
125     for (const auto& blob : testBlobs)
126     {
127         ASSERT_TRUE(handler->canHandleBlob(blob));
128 
129         blobs::BlobMeta meta = {};
130         EXPECT_TRUE(handler->stat(blob, &meta));
131         EXPECT_EQ(expectedIdleMeta, meta);
132     }
133 }
134 
135 /*
136  * writemeta(session)
137  */
TEST_F(FirmwareHandlerUpdateCompletedTest,WriteMetaToUpdateBlobReturnsFailure)138 TEST_F(FirmwareHandlerUpdateCompletedTest, WriteMetaToUpdateBlobReturnsFailure)
139 {
140     getToUpdateCompleted(ActionStatus::success);
141 
142     EXPECT_FALSE(handler->writeMeta(session, 0, {0x01}));
143 }
144 
145 /*
146  * write(session)
147  */
TEST_F(FirmwareHandlerUpdateCompletedTest,WriteToUpdateBlobReturnsFailure)148 TEST_F(FirmwareHandlerUpdateCompletedTest, WriteToUpdateBlobReturnsFailure)
149 {
150     getToUpdateCompleted(ActionStatus::success);
151 
152     EXPECT_FALSE(handler->write(session, 0, {0x01}));
153 }
154 
155 /*
156  * commit(session) - returns failure
157  */
TEST_F(FirmwareHandlerUpdateCompletedTest,CommitOnUpdateBlobAfterSuccessReturnsFailure)158 TEST_F(FirmwareHandlerUpdateCompletedTest,
159        CommitOnUpdateBlobAfterSuccessReturnsFailure)
160 {
161     getToUpdateCompleted(ActionStatus::success);
162 
163     EXPECT_CALL(*updateMockPtr, trigger()).Times(0);
164     EXPECT_FALSE(handler->commit(session, {}));
165 }
166 
TEST_F(FirmwareHandlerUpdateCompletedTest,CommitOnUpdateBlobAfterFailureReturnsFailure)167 TEST_F(FirmwareHandlerUpdateCompletedTest,
168        CommitOnUpdateBlobAfterFailureReturnsFailure)
169 {
170     getToUpdateCompleted(ActionStatus::failed);
171 
172     EXPECT_CALL(*updateMockPtr, trigger()).Times(0);
173     EXPECT_FALSE(handler->commit(session, {}));
174 }
175 
176 /*
177  * read(session) - nothing to read here.
178  */
TEST_F(FirmwareHandlerUpdateCompletedTest,ReadingFromUpdateBlobReturnsNothing)179 TEST_F(FirmwareHandlerUpdateCompletedTest, ReadingFromUpdateBlobReturnsNothing)
180 {
181     getToUpdateCompleted(ActionStatus::success);
182 
183     EXPECT_THAT(handler->read(session, 0, 1), IsEmpty());
184 }
185 
186 /*
187  * getBlobIds
188  * canHandleBlob(blob)
189  */
TEST_F(FirmwareHandlerUpdateCompletedTest,GetBlobListProvidesExpectedBlobs)190 TEST_F(FirmwareHandlerUpdateCompletedTest, GetBlobListProvidesExpectedBlobs)
191 {
192     getToUpdateCompleted(ActionStatus::success);
193 
194     EXPECT_THAT(
195         handler->getBlobIds(),
196         UnorderedElementsAreArray(
197             {updateBlobId, hashBlobId, activeImageBlobId, staticLayoutBlobId}));
198 }
199 
200 /*
201  * close(session) - closes everything out and returns to state not-yet-started.
202  * It doesn't go and clean out any update artifacts that may be present on the
203  * system.  It's up to the update implementation to deal with this before
204  * marking complete.
205  */
TEST_F(FirmwareHandlerUpdateCompletedTest,ClosingOnUpdateBlobIdAfterSuccessReturnsToNotYetStartedAndCleansBlobList)206 TEST_F(FirmwareHandlerUpdateCompletedTest,
207        ClosingOnUpdateBlobIdAfterSuccessReturnsToNotYetStartedAndCleansBlobList)
208 {
209     getToUpdateCompleted(ActionStatus::success);
210 
211     handler->close(session);
212     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
213 
214     EXPECT_THAT(handler->getBlobIds(),
215                 UnorderedElementsAreArray(startingBlobs));
216 }
217 
TEST_F(FirmwareHandlerUpdateCompletedTest,ClosingOnUpdateBlobIdAfterFailureReturnsToNotYetStartedAndCleansBlobList)218 TEST_F(FirmwareHandlerUpdateCompletedTest,
219        ClosingOnUpdateBlobIdAfterFailureReturnsToNotYetStartedAndCleansBlobList)
220 {
221     getToUpdateCompleted(ActionStatus::failed);
222 
223     handler->close(session);
224     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
225 
226     EXPECT_THAT(handler->getBlobIds(),
227                 UnorderedElementsAreArray(startingBlobs));
228 }
229 
230 /*
231  * deleteBlob(blob)
232  */
TEST_F(FirmwareHandlerUpdateCompletedTest,DeleteBlobReturnsFalse)233 TEST_F(FirmwareHandlerUpdateCompletedTest, DeleteBlobReturnsFalse)
234 {
235     /* Try deleting all blobs, it doesn't really matter which though because you
236      * cannot close out an open session, therefore you must fail to delete
237      * anything unless everything is closed.
238      */
239     getToUpdateCompleted(ActionStatus::success);
240 
241     auto blobs = handler->getBlobIds();
242     for (const auto& b : blobs)
243     {
244         EXPECT_FALSE(handler->deleteBlob(b));
245     }
246 }
247 
248 /*
249  * expire(session)
250  */
TEST_F(FirmwareHandlerUpdateCompletedTest,ExpireOnUpdateCompletedAbortsProcess)251 TEST_F(FirmwareHandlerUpdateCompletedTest, ExpireOnUpdateCompletedAbortsProcess)
252 {
253     getToUpdateCompleted(ActionStatus::success);
254 
255     ASSERT_TRUE(handler->expire(session));
256     EXPECT_THAT(handler->getBlobIds(),
257                 UnorderedElementsAreArray(startingBlobs));
258 
259     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
260 }
261 
262 } // namespace
263 } // namespace ipmi_flash
264