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 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 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 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 149 TEST(SoftwareUpdate, TestSoftwareUpdateSuccess) 150 { 151 const int fd = 152 makeUpdateFd(exampleCompatibleHardware, exampleVendorIANA, false); 153 154 testcaseSoftwareUpdateCommon(fd, true); 155 } 156 157 TEST(SoftwareUpdate, TestSoftwareUpdateFailureWrongCompatible) 158 { 159 const int fd = makeUpdateFd("not_compatible", exampleVendorIANA, false); 160 161 testcaseSoftwareUpdateCommon(fd, false); 162 } 163 164 TEST(SoftwareUpdate, TestSoftwareUpdateFailureWrongVendorIANA) 165 { 166 const int fd = makeUpdateFd(exampleCompatibleHardware, 0x03289, false); 167 168 testcaseSoftwareUpdateCommon(fd, false); 169 } 170 171 TEST(SoftwareUpdate, TestSoftwareUpdateFailureCorruptedPackage) 172 { 173 const int fd = 174 makeUpdateFd(exampleCompatibleHardware, exampleVendorIANA, true); 175 176 testcaseSoftwareUpdateCommon(fd, false); 177 } 178