xref: /openbmc/phosphor-bmc-code-mgmt/test/common/software/software_update.cpp (revision f53466770f7fdbb764232992e31797590ff1a42b)
1*f5346677SAlexander Hansen 
2*f5346677SAlexander Hansen #include "../exampledevice/example_device.hpp"
3*f5346677SAlexander Hansen #include "test/create_package/create_pldm_fw_package.hpp"
4*f5346677SAlexander Hansen 
5*f5346677SAlexander Hansen #include <fcntl.h>
6*f5346677SAlexander Hansen #include <inttypes.h>
7*f5346677SAlexander Hansen #include <sys/mman.h>
8*f5346677SAlexander Hansen #include <unistd.h>
9*f5346677SAlexander Hansen 
10*f5346677SAlexander Hansen #include <phosphor-logging/lg2.hpp>
11*f5346677SAlexander Hansen #include <sdbusplus/async/context.hpp>
12*f5346677SAlexander Hansen #include <xyz/openbmc_project/Association/Definitions/client.hpp>
13*f5346677SAlexander Hansen #include <xyz/openbmc_project/Software/Update/client.hpp>
14*f5346677SAlexander Hansen #include <xyz/openbmc_project/Software/Version/client.hpp>
15*f5346677SAlexander Hansen 
16*f5346677SAlexander Hansen #include <cstdlib>
17*f5346677SAlexander Hansen #include <cstring>
18*f5346677SAlexander Hansen 
19*f5346677SAlexander Hansen #include <gtest/gtest.h>
20*f5346677SAlexander Hansen 
21*f5346677SAlexander Hansen PHOSPHOR_LOG2_USING;
22*f5346677SAlexander Hansen 
23*f5346677SAlexander Hansen using namespace phosphor::software;
24*f5346677SAlexander Hansen using namespace phosphor::software::example_device;
25*f5346677SAlexander Hansen 
26*f5346677SAlexander Hansen using SoftwareActivationProgress =
27*f5346677SAlexander Hansen     sdbusplus::aserver::xyz::openbmc_project::software::ActivationProgress<
28*f5346677SAlexander Hansen         Software>;
29*f5346677SAlexander Hansen 
testSoftwareUpdateCommon(sdbusplus::async::context & ctx,int fd,bool expectNewVersion)30*f5346677SAlexander Hansen sdbusplus::async::task<> testSoftwareUpdateCommon(
31*f5346677SAlexander Hansen     sdbusplus::async::context& ctx, int fd, bool expectNewVersion)
32*f5346677SAlexander Hansen {
33*f5346677SAlexander Hansen     ExampleCodeUpdater exampleUpdater(ctx, true, "v12.345");
34*f5346677SAlexander Hansen 
35*f5346677SAlexander Hansen     auto& device = exampleUpdater.getDevice();
36*f5346677SAlexander Hansen 
37*f5346677SAlexander Hansen     device->softwareCurrent->enableUpdate({RequestedApplyTimes::Immediate});
38*f5346677SAlexander Hansen 
39*f5346677SAlexander Hansen     std::string objPathCurrentSoftware =
40*f5346677SAlexander Hansen         reinterpret_cast<ExampleSoftware*>(device->softwareCurrent.get())
41*f5346677SAlexander Hansen             ->objectPath;
42*f5346677SAlexander Hansen 
43*f5346677SAlexander Hansen     auto busName = exampleUpdater.getBusName();
44*f5346677SAlexander Hansen 
45*f5346677SAlexander Hansen     // go via dbus to call the dbus method to start the update
46*f5346677SAlexander Hansen     auto client =
47*f5346677SAlexander Hansen         sdbusplus::client::xyz::openbmc_project::software::Update<>(ctx)
48*f5346677SAlexander Hansen             .service(busName)
49*f5346677SAlexander Hansen             .path(objPathCurrentSoftware);
50*f5346677SAlexander Hansen 
51*f5346677SAlexander Hansen     sdbusplus::message::object_path objPathNewSoftware =
52*f5346677SAlexander Hansen         co_await client.start_update(fd, RequestedApplyTimes::Immediate);
53*f5346677SAlexander Hansen 
54*f5346677SAlexander Hansen     EXPECT_NE(objPathNewSoftware, objPathCurrentSoftware);
55*f5346677SAlexander Hansen 
56*f5346677SAlexander Hansen     auto clientNewVersion =
57*f5346677SAlexander Hansen         sdbusplus::client::xyz::openbmc_project::software::Version<>(ctx)
58*f5346677SAlexander Hansen             .service(busName)
59*f5346677SAlexander Hansen             .path(objPathNewSoftware.str);
60*f5346677SAlexander Hansen 
61*f5346677SAlexander Hansen     // call the client for new version to appear within timeout
62*f5346677SAlexander Hansen     std::string newVersion;
63*f5346677SAlexander Hansen     ssize_t timeout = 500;
64*f5346677SAlexander Hansen     while (timeout > 0)
65*f5346677SAlexander Hansen     {
66*f5346677SAlexander Hansen         co_await sdbusplus::async::sleep_for(ctx,
67*f5346677SAlexander Hansen                                              std::chrono::milliseconds(50));
68*f5346677SAlexander Hansen         try
69*f5346677SAlexander Hansen         {
70*f5346677SAlexander Hansen             debug("Test: querying new version");
71*f5346677SAlexander Hansen             newVersion = co_await clientNewVersion.version();
72*f5346677SAlexander Hansen             break;
73*f5346677SAlexander Hansen         }
74*f5346677SAlexander Hansen         catch (std::exception& _)
75*f5346677SAlexander Hansen         {
76*f5346677SAlexander Hansen             timeout -= 50;
77*f5346677SAlexander Hansen         }
78*f5346677SAlexander Hansen     }
79*f5346677SAlexander Hansen 
80*f5346677SAlexander Hansen     EXPECT_EQ(timeout > 0, expectNewVersion);
81*f5346677SAlexander Hansen 
82*f5346677SAlexander Hansen     // assert that update function was called
83*f5346677SAlexander Hansen     EXPECT_EQ(device->deviceSpecificUpdateFunctionCalled, expectNewVersion);
84*f5346677SAlexander Hansen 
85*f5346677SAlexander Hansen     if (expectNewVersion)
86*f5346677SAlexander Hansen     {
87*f5346677SAlexander Hansen         EXPECT_EQ(newVersion, exampleVersion);
88*f5346677SAlexander Hansen         EXPECT_EQ(device->softwareCurrent->swid, objPathNewSoftware.filename());
89*f5346677SAlexander Hansen     }
90*f5346677SAlexander Hansen 
91*f5346677SAlexander Hansen     ctx.request_stop();
92*f5346677SAlexander Hansen 
93*f5346677SAlexander Hansen     co_return;
94*f5346677SAlexander Hansen }
95*f5346677SAlexander Hansen 
makeUpdateFd(const std::string & compatible,const uint32_t vendorIANA,bool corrupted)96*f5346677SAlexander Hansen static int makeUpdateFd(const std::string& compatible,
97*f5346677SAlexander Hansen                         const uint32_t vendorIANA, bool corrupted)
98*f5346677SAlexander Hansen {
99*f5346677SAlexander Hansen     int fd = memfd_create("test_memfd", 0);
100*f5346677SAlexander Hansen     EXPECT_GE(fd, 0);
101*f5346677SAlexander Hansen 
102*f5346677SAlexander Hansen     if (fd < 0)
103*f5346677SAlexander Hansen     {
104*f5346677SAlexander Hansen         return fd;
105*f5346677SAlexander Hansen     }
106*f5346677SAlexander Hansen 
107*f5346677SAlexander Hansen     debug("create fd {FD}", "FD", fd);
108*f5346677SAlexander Hansen 
109*f5346677SAlexander Hansen     uint8_t component_image[] = {0x12, 0x34, 0x83, 0x21};
110*f5346677SAlexander Hansen 
111*f5346677SAlexander Hansen     size_t size_out = 0;
112*f5346677SAlexander Hansen     std::unique_ptr<uint8_t[]> buf = create_pldm_package_buffer(
113*f5346677SAlexander Hansen         component_image, sizeof(component_image),
114*f5346677SAlexander Hansen         std::optional<uint32_t>(vendorIANA),
115*f5346677SAlexander Hansen         std::optional<std::string>(compatible), size_out);
116*f5346677SAlexander Hansen 
117*f5346677SAlexander Hansen     if (corrupted)
118*f5346677SAlexander Hansen     {
119*f5346677SAlexander Hansen         buf[3] = 0x8;
120*f5346677SAlexander Hansen         buf[9] = 0x3;
121*f5346677SAlexander Hansen     }
122*f5346677SAlexander Hansen 
123*f5346677SAlexander Hansen     ssize_t bytes_written = write(fd, (void*)buf.get(), size_out);
124*f5346677SAlexander Hansen     EXPECT_NE(bytes_written, -1)
125*f5346677SAlexander Hansen         << "Failed to write to memfd: " << strerror(errno);
126*f5346677SAlexander Hansen     if (bytes_written == -1)
127*f5346677SAlexander Hansen     {
128*f5346677SAlexander Hansen         close(fd);
129*f5346677SAlexander Hansen         return -1;
130*f5346677SAlexander Hansen     }
131*f5346677SAlexander Hansen 
132*f5346677SAlexander Hansen     EXPECT_EQ(lseek(fd, 0, SEEK_SET), 0)
133*f5346677SAlexander Hansen         << "could not seek to the beginning of the file";
134*f5346677SAlexander Hansen     return fd;
135*f5346677SAlexander Hansen }
136*f5346677SAlexander Hansen 
testcaseSoftwareUpdateCommon(const int fd,bool expectSuccess)137*f5346677SAlexander Hansen void testcaseSoftwareUpdateCommon(const int fd, bool expectSuccess)
138*f5346677SAlexander Hansen {
139*f5346677SAlexander Hansen     ASSERT_GE(fd, 0);
140*f5346677SAlexander Hansen 
141*f5346677SAlexander Hansen     sdbusplus::async::context ctx;
142*f5346677SAlexander Hansen 
143*f5346677SAlexander Hansen     ctx.spawn(testSoftwareUpdateCommon(ctx, fd, expectSuccess));
144*f5346677SAlexander Hansen 
145*f5346677SAlexander Hansen     ctx.run();
146*f5346677SAlexander Hansen     close(fd);
147*f5346677SAlexander Hansen }
148*f5346677SAlexander Hansen 
TEST(SoftwareUpdate,TestSoftwareUpdateSuccess)149*f5346677SAlexander Hansen TEST(SoftwareUpdate, TestSoftwareUpdateSuccess)
150*f5346677SAlexander Hansen {
151*f5346677SAlexander Hansen     const int fd =
152*f5346677SAlexander Hansen         makeUpdateFd(exampleCompatibleHardware, exampleVendorIANA, false);
153*f5346677SAlexander Hansen 
154*f5346677SAlexander Hansen     testcaseSoftwareUpdateCommon(fd, true);
155*f5346677SAlexander Hansen }
156*f5346677SAlexander Hansen 
TEST(SoftwareUpdate,TestSoftwareUpdateFailureWrongCompatible)157*f5346677SAlexander Hansen TEST(SoftwareUpdate, TestSoftwareUpdateFailureWrongCompatible)
158*f5346677SAlexander Hansen {
159*f5346677SAlexander Hansen     const int fd = makeUpdateFd("not_compatible", exampleVendorIANA, false);
160*f5346677SAlexander Hansen 
161*f5346677SAlexander Hansen     testcaseSoftwareUpdateCommon(fd, false);
162*f5346677SAlexander Hansen }
163*f5346677SAlexander Hansen 
TEST(SoftwareUpdate,TestSoftwareUpdateFailureWrongVendorIANA)164*f5346677SAlexander Hansen TEST(SoftwareUpdate, TestSoftwareUpdateFailureWrongVendorIANA)
165*f5346677SAlexander Hansen {
166*f5346677SAlexander Hansen     const int fd = makeUpdateFd(exampleCompatibleHardware, 0x03289, false);
167*f5346677SAlexander Hansen 
168*f5346677SAlexander Hansen     testcaseSoftwareUpdateCommon(fd, false);
169*f5346677SAlexander Hansen }
170*f5346677SAlexander Hansen 
TEST(SoftwareUpdate,TestSoftwareUpdateFailureCorruptedPackage)171*f5346677SAlexander Hansen TEST(SoftwareUpdate, TestSoftwareUpdateFailureCorruptedPackage)
172*f5346677SAlexander Hansen {
173*f5346677SAlexander Hansen     const int fd =
174*f5346677SAlexander Hansen         makeUpdateFd(exampleCompatibleHardware, exampleVendorIANA, true);
175*f5346677SAlexander Hansen 
176*f5346677SAlexander Hansen     testcaseSoftwareUpdateCommon(fd, false);
177*f5346677SAlexander Hansen }
178