xref: /openbmc/phosphor-bmc-code-mgmt/test/common/device/device.cpp (revision 3a31f0ac322abb081603e04e3eb2e665e8814673)
1*3a31f0acSAlexander Hansen #include "../exampledevice/example_device.hpp"
2*3a31f0acSAlexander Hansen #include "test/create_package/create_pldm_fw_package.hpp"
3*3a31f0acSAlexander Hansen 
4*3a31f0acSAlexander Hansen #include <sys/mman.h>
5*3a31f0acSAlexander Hansen 
6*3a31f0acSAlexander Hansen #include <phosphor-logging/lg2.hpp>
7*3a31f0acSAlexander Hansen #include <sdbusplus/asio/connection.hpp>
8*3a31f0acSAlexander Hansen #include <sdbusplus/asio/object_server.hpp>
9*3a31f0acSAlexander Hansen #include <sdbusplus/async.hpp>
10*3a31f0acSAlexander Hansen #include <sdbusplus/server.hpp>
11*3a31f0acSAlexander Hansen #include <xyz/openbmc_project/Association/Definitions/server.hpp>
12*3a31f0acSAlexander Hansen #include <xyz/openbmc_project/Software/Update/server.hpp>
13*3a31f0acSAlexander Hansen 
14*3a31f0acSAlexander Hansen #include <memory>
15*3a31f0acSAlexander Hansen 
16*3a31f0acSAlexander Hansen #include <gtest/gtest.h>
17*3a31f0acSAlexander Hansen 
18*3a31f0acSAlexander Hansen PHOSPHOR_LOG2_USING;
19*3a31f0acSAlexander Hansen 
20*3a31f0acSAlexander Hansen using namespace phosphor::software;
21*3a31f0acSAlexander Hansen using namespace phosphor::software::example_device;
22*3a31f0acSAlexander Hansen using SoftwareActivationProgress =
23*3a31f0acSAlexander Hansen     sdbusplus::aserver::xyz::openbmc_project::software::ActivationProgress<
24*3a31f0acSAlexander Hansen         Software>;
25*3a31f0acSAlexander Hansen 
26*3a31f0acSAlexander Hansen class DeviceTest : public testing::Test
27*3a31f0acSAlexander Hansen {
28*3a31f0acSAlexander Hansen   protected:
29*3a31f0acSAlexander Hansen     DeviceTest() :
30*3a31f0acSAlexander Hansen         exampleUpdater(ctx, true, "vUnknown"),
31*3a31f0acSAlexander Hansen         device(exampleUpdater.getDevice())
32*3a31f0acSAlexander Hansen     {}
33*3a31f0acSAlexander Hansen     ~DeviceTest() noexcept override {}
34*3a31f0acSAlexander Hansen 
35*3a31f0acSAlexander Hansen     sdbusplus::async::context ctx;
36*3a31f0acSAlexander Hansen     ExampleCodeUpdater exampleUpdater;
37*3a31f0acSAlexander Hansen     std::unique_ptr<ExampleDevice>& device;
38*3a31f0acSAlexander Hansen 
39*3a31f0acSAlexander Hansen   public:
40*3a31f0acSAlexander Hansen     DeviceTest(const DeviceTest&) = delete;
41*3a31f0acSAlexander Hansen     DeviceTest(DeviceTest&&) = delete;
42*3a31f0acSAlexander Hansen     DeviceTest& operator=(const DeviceTest&) = delete;
43*3a31f0acSAlexander Hansen     DeviceTest& operator=(DeviceTest&&) = delete;
44*3a31f0acSAlexander Hansen 
45*3a31f0acSAlexander Hansen     // @returns memfd
46*3a31f0acSAlexander Hansen     // @returns -1 on failure
47*3a31f0acSAlexander Hansen     static int createTestPkgMemfd();
48*3a31f0acSAlexander Hansen };
49*3a31f0acSAlexander Hansen 
50*3a31f0acSAlexander Hansen int DeviceTest::createTestPkgMemfd()
51*3a31f0acSAlexander Hansen {
52*3a31f0acSAlexander Hansen     uint8_t component_image[] = {0x12, 0x34, 0x83, 0x21};
53*3a31f0acSAlexander Hansen 
54*3a31f0acSAlexander Hansen     size_t sizeOut;
55*3a31f0acSAlexander Hansen     std::unique_ptr<uint8_t[]> buf = create_pldm_package_buffer(
56*3a31f0acSAlexander Hansen         component_image, sizeof(component_image),
57*3a31f0acSAlexander Hansen         std::optional<uint32_t>(exampleVendorIANA),
58*3a31f0acSAlexander Hansen         std::optional<std::string>(exampleCompatibleHardware), sizeOut);
59*3a31f0acSAlexander Hansen 
60*3a31f0acSAlexander Hansen     const int fd = memfd_create("test_memfd", 0);
61*3a31f0acSAlexander Hansen 
62*3a31f0acSAlexander Hansen     EXPECT_TRUE(fd >= 0);
63*3a31f0acSAlexander Hansen 
64*3a31f0acSAlexander Hansen     debug("create fd {FD}", "FD", fd);
65*3a31f0acSAlexander Hansen 
66*3a31f0acSAlexander Hansen     if (write(fd, (void*)buf.get(), sizeOut) == -1)
67*3a31f0acSAlexander Hansen     {
68*3a31f0acSAlexander Hansen         std::cerr << "Failed to write to memfd: " << strerror(errno)
69*3a31f0acSAlexander Hansen                   << std::endl;
70*3a31f0acSAlexander Hansen         close(fd);
71*3a31f0acSAlexander Hansen         EXPECT_TRUE(false);
72*3a31f0acSAlexander Hansen         return -1;
73*3a31f0acSAlexander Hansen     }
74*3a31f0acSAlexander Hansen 
75*3a31f0acSAlexander Hansen     if (lseek(fd, 0, SEEK_SET) != 0)
76*3a31f0acSAlexander Hansen     {
77*3a31f0acSAlexander Hansen         error("could not seek to the beginning of the file");
78*3a31f0acSAlexander Hansen         close(fd);
79*3a31f0acSAlexander Hansen         EXPECT_TRUE(false);
80*3a31f0acSAlexander Hansen         return -1;
81*3a31f0acSAlexander Hansen     }
82*3a31f0acSAlexander Hansen 
83*3a31f0acSAlexander Hansen     return fd;
84*3a31f0acSAlexander Hansen }
85*3a31f0acSAlexander Hansen 
86*3a31f0acSAlexander Hansen TEST_F(DeviceTest, TestDeviceConstructor)
87*3a31f0acSAlexander Hansen {
88*3a31f0acSAlexander Hansen     EXPECT_TRUE(device->getEMConfigType().starts_with("Nop"));
89*3a31f0acSAlexander Hansen 
90*3a31f0acSAlexander Hansen     // the software version is initialized
91*3a31f0acSAlexander Hansen     EXPECT_NE(device->softwareCurrent, nullptr);
92*3a31f0acSAlexander Hansen 
93*3a31f0acSAlexander Hansen     // there is no pending update
94*3a31f0acSAlexander Hansen     EXPECT_EQ(device->softwarePending, nullptr);
95*3a31f0acSAlexander Hansen }
96*3a31f0acSAlexander Hansen 
97*3a31f0acSAlexander Hansen sdbusplus::async::task<> testDeviceStartUpdateCommon(
98*3a31f0acSAlexander Hansen     sdbusplus::async::context& ctx, std::unique_ptr<ExampleDevice>& device,
99*3a31f0acSAlexander Hansen     RequestedApplyTimes applyTime)
100*3a31f0acSAlexander Hansen {
101*3a31f0acSAlexander Hansen     const Software* oldSoftware = device->softwareCurrent.get();
102*3a31f0acSAlexander Hansen 
103*3a31f0acSAlexander Hansen     const int fd = DeviceTest::createTestPkgMemfd();
104*3a31f0acSAlexander Hansen 
105*3a31f0acSAlexander Hansen     EXPECT_TRUE(fd >= 0);
106*3a31f0acSAlexander Hansen 
107*3a31f0acSAlexander Hansen     if (fd < 0)
108*3a31f0acSAlexander Hansen     {
109*3a31f0acSAlexander Hansen         co_return;
110*3a31f0acSAlexander Hansen     }
111*3a31f0acSAlexander Hansen 
112*3a31f0acSAlexander Hansen     std::unique_ptr<Software> softwareUpdate =
113*3a31f0acSAlexander Hansen         std::make_unique<Software>(ctx, *device);
114*3a31f0acSAlexander Hansen 
115*3a31f0acSAlexander Hansen     const Software* newSoftware = softwareUpdate.get();
116*3a31f0acSAlexander Hansen 
117*3a31f0acSAlexander Hansen     co_await device->startUpdateAsync(fd, applyTime, std::move(softwareUpdate));
118*3a31f0acSAlexander Hansen 
119*3a31f0acSAlexander Hansen     EXPECT_TRUE(device->deviceSpecificUpdateFunctionCalled);
120*3a31f0acSAlexander Hansen 
121*3a31f0acSAlexander Hansen     if (applyTime == RequestedApplyTimes::Immediate)
122*3a31f0acSAlexander Hansen     {
123*3a31f0acSAlexander Hansen         EXPECT_NE(device->softwareCurrent.get(), oldSoftware);
124*3a31f0acSAlexander Hansen         EXPECT_EQ(device->softwareCurrent.get(), newSoftware);
125*3a31f0acSAlexander Hansen 
126*3a31f0acSAlexander Hansen         EXPECT_FALSE(device->softwarePending);
127*3a31f0acSAlexander Hansen     }
128*3a31f0acSAlexander Hansen 
129*3a31f0acSAlexander Hansen     if (applyTime == RequestedApplyTimes::OnReset)
130*3a31f0acSAlexander Hansen     {
131*3a31f0acSAlexander Hansen         // assert that the old software is still the running version,
132*3a31f0acSAlexander Hansen         // since the apply time is 'OnReset'
133*3a31f0acSAlexander Hansen         EXPECT_EQ(device->softwareCurrent.get(), oldSoftware);
134*3a31f0acSAlexander Hansen 
135*3a31f0acSAlexander Hansen         // assert that the updated software is present
136*3a31f0acSAlexander Hansen         EXPECT_EQ(device->softwarePending.get(), newSoftware);
137*3a31f0acSAlexander Hansen     }
138*3a31f0acSAlexander Hansen 
139*3a31f0acSAlexander Hansen     close(fd);
140*3a31f0acSAlexander Hansen 
141*3a31f0acSAlexander Hansen     ctx.request_stop();
142*3a31f0acSAlexander Hansen 
143*3a31f0acSAlexander Hansen     co_return;
144*3a31f0acSAlexander Hansen }
145*3a31f0acSAlexander Hansen 
146*3a31f0acSAlexander Hansen TEST_F(DeviceTest, TestDeviceStartUpdateImmediateSuccess)
147*3a31f0acSAlexander Hansen {
148*3a31f0acSAlexander Hansen     ctx.spawn(testDeviceStartUpdateCommon(ctx, device,
149*3a31f0acSAlexander Hansen                                           RequestedApplyTimes::Immediate));
150*3a31f0acSAlexander Hansen     ctx.run();
151*3a31f0acSAlexander Hansen }
152*3a31f0acSAlexander Hansen 
153*3a31f0acSAlexander Hansen TEST_F(DeviceTest, TestDeviceStartUpdateOnResetSuccess)
154*3a31f0acSAlexander Hansen {
155*3a31f0acSAlexander Hansen     ctx.spawn(
156*3a31f0acSAlexander Hansen         testDeviceStartUpdateCommon(ctx, device, RequestedApplyTimes::OnReset));
157*3a31f0acSAlexander Hansen     ctx.run();
158*3a31f0acSAlexander Hansen }
159*3a31f0acSAlexander Hansen 
160*3a31f0acSAlexander Hansen sdbusplus::async::task<> testDeviceStartUpdateInvalidFD(
161*3a31f0acSAlexander Hansen     sdbusplus::async::context& ctx, std::unique_ptr<ExampleDevice>& device)
162*3a31f0acSAlexander Hansen {
163*3a31f0acSAlexander Hansen     std::unique_ptr<SoftwareActivationProgress> activationProgress =
164*3a31f0acSAlexander Hansen         std::make_unique<SoftwareActivationProgress>(ctx, "/");
165*3a31f0acSAlexander Hansen 
166*3a31f0acSAlexander Hansen     sdbusplus::message::unix_fd image;
167*3a31f0acSAlexander Hansen     image.fd = -1;
168*3a31f0acSAlexander Hansen 
169*3a31f0acSAlexander Hansen     std::unique_ptr<Software> softwareUpdate =
170*3a31f0acSAlexander Hansen         std::make_unique<Software>(ctx, *device);
171*3a31f0acSAlexander Hansen 
172*3a31f0acSAlexander Hansen     co_await device->startUpdateAsync(image, RequestedApplyTimes::Immediate,
173*3a31f0acSAlexander Hansen                                       std::move(softwareUpdate));
174*3a31f0acSAlexander Hansen 
175*3a31f0acSAlexander Hansen     // assert the bad file descriptor was caught and we did not proceed
176*3a31f0acSAlexander Hansen     EXPECT_FALSE(device->deviceSpecificUpdateFunctionCalled);
177*3a31f0acSAlexander Hansen 
178*3a31f0acSAlexander Hansen     ctx.request_stop();
179*3a31f0acSAlexander Hansen 
180*3a31f0acSAlexander Hansen     co_return;
181*3a31f0acSAlexander Hansen }
182*3a31f0acSAlexander Hansen 
183*3a31f0acSAlexander Hansen TEST_F(DeviceTest, TestDeviceStartUpdateInvalidFD)
184*3a31f0acSAlexander Hansen {
185*3a31f0acSAlexander Hansen     ctx.spawn(testDeviceStartUpdateInvalidFD(ctx, device));
186*3a31f0acSAlexander Hansen     ctx.run();
187*3a31f0acSAlexander Hansen }
188*3a31f0acSAlexander Hansen 
189*3a31f0acSAlexander Hansen sdbusplus::async::task<> testDeviceSpecificUpdateFunction(
190*3a31f0acSAlexander Hansen     sdbusplus::async::context& ctx, std::unique_ptr<ExampleDevice>& device)
191*3a31f0acSAlexander Hansen {
192*3a31f0acSAlexander Hansen     uint8_t buffer[10];
193*3a31f0acSAlexander Hansen     size_t buffer_size = 10;
194*3a31f0acSAlexander Hansen 
195*3a31f0acSAlexander Hansen     auto previousVersion = device->softwareCurrent->swid;
196*3a31f0acSAlexander Hansen 
197*3a31f0acSAlexander Hansen     bool success =
198*3a31f0acSAlexander Hansen         co_await device->updateDevice((const uint8_t*)buffer, buffer_size);
199*3a31f0acSAlexander Hansen 
200*3a31f0acSAlexander Hansen     EXPECT_TRUE(success);
201*3a31f0acSAlexander Hansen 
202*3a31f0acSAlexander Hansen     EXPECT_NE(device->softwareCurrent, nullptr);
203*3a31f0acSAlexander Hansen     EXPECT_EQ(device->softwarePending, nullptr);
204*3a31f0acSAlexander Hansen 
205*3a31f0acSAlexander Hansen     ctx.request_stop();
206*3a31f0acSAlexander Hansen 
207*3a31f0acSAlexander Hansen     co_return;
208*3a31f0acSAlexander Hansen }
209*3a31f0acSAlexander Hansen 
210*3a31f0acSAlexander Hansen TEST_F(DeviceTest, TestDeviceSpecificUpdateFunction)
211*3a31f0acSAlexander Hansen {
212*3a31f0acSAlexander Hansen     // NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch)
213*3a31f0acSAlexander Hansen     ctx.spawn(testDeviceSpecificUpdateFunction(ctx, device));
214*3a31f0acSAlexander Hansen     // NOLINTEND(clang-analyzer-core.uninitialized.Branch)
215*3a31f0acSAlexander Hansen     ctx.run();
216*3a31f0acSAlexander Hansen }
217