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