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