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