1 /* The goal of these tests is to verify the behavior of all blob commands given
2  * the current state is updateStarted.  This state is achieved as an exit from
3  * updatePending.
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 
40 class FirmwareHandlerUpdateStartedTest : public IpmiOnlyFirmwareStaticTest
41 {};
42 
43 /*
44  * open(blob)
45  */
46 TEST_F(FirmwareHandlerUpdateStartedTest, AttemptToOpenFilesReturnsFailure)
47 {
48     /* In state updateStarted a file is open, which means no others can be. */
49     getToUpdateStarted();
50 
51     auto blobsToOpen = handler->getBlobIds();
52     for (const auto& blob : blobsToOpen)
53     {
54         EXPECT_FALSE(handler->open(session + 1, flags, blob));
55     }
56 }
57 
58 /* canHandleBlob(blob)
59  * getBlobIds
60  */
61 TEST_F(FirmwareHandlerUpdateStartedTest, VerifyListOfBlobs)
62 {
63     getToUpdateStarted();
64 
65     EXPECT_THAT(
66         handler->getBlobIds(),
67         UnorderedElementsAreArray(
68             {updateBlobId, hashBlobId, activeImageBlobId, staticLayoutBlobId}));
69 }
70 
71 /*
72  * deleteBlob(blob)
73  */
74 TEST_F(FirmwareHandlerUpdateStartedTest, DeleteBlobReturnsFalse)
75 {
76     /* Try deleting all blobs, it doesn't really matter which though because you
77      * cannot close out an open session, therefore you must fail to delete
78      * anything unless everything is closed.
79      */
80     getToUpdateStarted();
81     auto blobs = handler->getBlobIds();
82     for (const auto& b : blobs)
83     {
84         EXPECT_FALSE(handler->deleteBlob(b));
85     }
86 }
87 
88 /*
89  * stat(blob)
90  */
91 TEST_F(FirmwareHandlerUpdateStartedTest, StatOnActiveImageReturnsFailure)
92 {
93     getToUpdateStarted();
94 
95     ASSERT_TRUE(handler->canHandleBlob(activeImageBlobId));
96 
97     blobs::BlobMeta meta;
98     EXPECT_FALSE(handler->stat(activeImageBlobId, &meta));
99 }
100 
101 TEST_F(FirmwareHandlerUpdateStartedTest, StatOnUpdateBlobReturnsFailure)
102 {
103     getToUpdateStarted();
104 
105     ASSERT_TRUE(handler->canHandleBlob(updateBlobId));
106 
107     blobs::BlobMeta meta;
108     EXPECT_FALSE(handler->stat(updateBlobId, &meta));
109 }
110 
111 TEST_F(FirmwareHandlerUpdateStartedTest, StatOnNormalBlobsReturnsSuccess)
112 {
113     getToUpdateStarted();
114 
115     std::vector<std::string> testBlobs = {staticLayoutBlobId, hashBlobId};
116     for (const auto& blob : testBlobs)
117     {
118         ASSERT_TRUE(handler->canHandleBlob(blob));
119 
120         blobs::BlobMeta meta = {};
121         EXPECT_TRUE(handler->stat(blob, &meta));
122         EXPECT_EQ(expectedIdleMeta, meta);
123     }
124 }
125 
126 /*
127  * writemeta(session)
128  */
129 TEST_F(FirmwareHandlerUpdateStartedTest, WriteMetaToUpdateBlobReturnsFailure)
130 {
131     getToUpdateStarted();
132     EXPECT_FALSE(handler->writeMeta(session, 0, {0x01}));
133 }
134 
135 /*
136  * write(session)
137  */
138 TEST_F(FirmwareHandlerUpdateStartedTest, WriteToUpdateBlobReturnsFailure)
139 {
140     getToUpdateStarted();
141     EXPECT_FALSE(handler->write(session, 0, {0x01}));
142 }
143 
144 /*
145  * read(session)
146  */
147 TEST_F(FirmwareHandlerUpdateStartedTest, ReadFromUpdateBlobReturnsEmpty)
148 {
149     getToUpdateStarted();
150     EXPECT_THAT(handler->read(session, 0, 1), IsEmpty());
151 }
152 
153 /*
154  * commit(session)
155  */
156 TEST_F(FirmwareHandlerUpdateStartedTest,
157        CallingCommitShouldReturnTrueAndHaveNoEffect)
158 {
159     getToUpdateStarted();
160     EXPECT_CALL(*updateMockPtr, trigger()).Times(0);
161 
162     EXPECT_TRUE(handler->commit(session, {}));
163     expectedState(FirmwareBlobHandler::UpdateState::updateStarted);
164 }
165 
166 /*
167  * stat(session) - this will trigger a check, and the state may change.
168  */
169 TEST_F(FirmwareHandlerUpdateStartedTest,
170        CallStatChecksActionStatusReturnsRunningDoesNotChangeState)
171 {
172     getToUpdateStarted();
173     EXPECT_CALL(*updateMockPtr, status())
174         .WillOnce(Return(ActionStatus::running));
175 
176     blobs::BlobMeta meta, expectedMeta = {};
177     expectedMeta.size = 0;
178     expectedMeta.blobState = flags | blobs::StateFlags::committing;
179     expectedMeta.metadata.push_back(
180         static_cast<std::uint8_t>(ActionStatus::running));
181 
182     EXPECT_TRUE(handler->stat(session, &meta));
183     EXPECT_EQ(expectedMeta, meta);
184     expectedState(FirmwareBlobHandler::UpdateState::updateStarted);
185 }
186 
187 TEST_F(FirmwareHandlerUpdateStartedTest,
188        CallStatChecksActionStatusReturnsFailedChangesStateToCompleted)
189 {
190     getToUpdateStarted();
191     EXPECT_CALL(*updateMockPtr, status())
192         .WillOnce(Return(ActionStatus::failed));
193 
194     blobs::BlobMeta meta, expectedMeta = {};
195     expectedMeta.size = 0;
196     expectedMeta.blobState = flags | blobs::StateFlags::commit_error;
197     expectedMeta.metadata.push_back(
198         static_cast<std::uint8_t>(ActionStatus::failed));
199 
200     EXPECT_TRUE(handler->stat(session, &meta));
201     EXPECT_EQ(expectedMeta, meta);
202     expectedState(FirmwareBlobHandler::UpdateState::updateCompleted);
203 }
204 
205 TEST_F(FirmwareHandlerUpdateStartedTest,
206        CallStatChecksActionStatusReturnsSuccessChangesStateToCompleted)
207 {
208     getToUpdateStarted();
209     EXPECT_CALL(*updateMockPtr, status())
210         .WillOnce(Return(ActionStatus::success));
211 
212     blobs::BlobMeta meta, expectedMeta = {};
213     expectedMeta.size = 0;
214     expectedMeta.blobState = flags | blobs::StateFlags::committed;
215     expectedMeta.metadata.push_back(
216         static_cast<std::uint8_t>(ActionStatus::success));
217 
218     EXPECT_TRUE(handler->stat(session, &meta));
219     EXPECT_EQ(expectedMeta, meta);
220     expectedState(FirmwareBlobHandler::UpdateState::updateCompleted);
221 }
222 
223 /*
224  * close(session) - this will abort.
225  */
226 TEST_F(FirmwareHandlerUpdateStartedTest, CloseOnUpdateDuringUpdateAbortsProcess)
227 {
228     getToUpdateStarted();
229     EXPECT_CALL(*updateMockPtr, abort()).Times(1);
230 
231     EXPECT_TRUE(handler->close(session));
232 
233     EXPECT_THAT(handler->getBlobIds(),
234                 UnorderedElementsAreArray(startingBlobs));
235 
236     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
237 }
238 
239 /*
240  * expire(session)
241  */
242 TEST_F(FirmwareHandlerUpdateStartedTest,
243        ExpireOnUpdateDuringUpdateAbortsProcess)
244 {
245     getToUpdateStarted();
246     EXPECT_CALL(*updateMockPtr, abort()).Times(0);
247 
248     ASSERT_TRUE(handler->expire(session));
249 
250     EXPECT_THAT(handler->getBlobIds(),
251                 UnorderedElementsAreArray(startingBlobs));
252 
253     expectedState(FirmwareBlobHandler::UpdateState::notYetStarted);
254 }
255 
256 } // namespace
257 } // namespace ipmi_flash
258