fw update: tests for software update
Tests for the software update flow.
Minimal PLDM packages are constructed in testcases and the update flow
is run on software instance.
These tests should check that the common code behaves as outlined in the
design [1]
References:
[1] https://github.com/openbmc/docs/blob/master/designs/code-update.md
Change-Id: Ibf473999b692a85dd86e4ab57a9a4c322257fc40
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
diff --git a/test/common/software/meson.build b/test/common/software/meson.build
index e56441b..318ff0f 100644
--- a/test/common/software/meson.build
+++ b/test/common/software/meson.build
@@ -3,6 +3,7 @@
'software_get_random_softwareid',
'software_config',
'software_association',
+ 'software_update',
'software_version',
'software',
]
diff --git a/test/common/software/software_update.cpp b/test/common/software/software_update.cpp
new file mode 100644
index 0000000..9c29fbb
--- /dev/null
+++ b/test/common/software/software_update.cpp
@@ -0,0 +1,177 @@
+
+#include "../exampledevice/example_device.hpp"
+#include "test/create_package/create_pldm_fw_package.hpp"
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/async/context.hpp>
+#include <xyz/openbmc_project/Association/Definitions/client.hpp>
+#include <xyz/openbmc_project/Software/Update/client.hpp>
+#include <xyz/openbmc_project/Software/Version/client.hpp>
+
+#include <cstdlib>
+#include <cstring>
+
+#include <gtest/gtest.h>
+
+PHOSPHOR_LOG2_USING;
+
+using namespace phosphor::software;
+using namespace phosphor::software::example_device;
+
+using SoftwareActivationProgress =
+ sdbusplus::aserver::xyz::openbmc_project::software::ActivationProgress<
+ Software>;
+
+sdbusplus::async::task<> testSoftwareUpdateCommon(
+ sdbusplus::async::context& ctx, int fd, bool expectNewVersion)
+{
+ ExampleCodeUpdater exampleUpdater(ctx, true, "v12.345");
+
+ auto& device = exampleUpdater.getDevice();
+
+ device->softwareCurrent->enableUpdate({RequestedApplyTimes::Immediate});
+
+ std::string objPathCurrentSoftware =
+ reinterpret_cast<ExampleSoftware*>(device->softwareCurrent.get())
+ ->objectPath;
+
+ auto busName = exampleUpdater.getBusName();
+
+ // go via dbus to call the dbus method to start the update
+ auto client =
+ sdbusplus::client::xyz::openbmc_project::software::Update<>(ctx)
+ .service(busName)
+ .path(objPathCurrentSoftware);
+
+ sdbusplus::message::object_path objPathNewSoftware =
+ co_await client.start_update(fd, RequestedApplyTimes::Immediate);
+
+ EXPECT_NE(objPathNewSoftware, objPathCurrentSoftware);
+
+ auto clientNewVersion =
+ sdbusplus::client::xyz::openbmc_project::software::Version<>(ctx)
+ .service(busName)
+ .path(objPathNewSoftware.str);
+
+ // call the client for new version to appear within timeout
+ std::string newVersion;
+ ssize_t timeout = 500;
+ while (timeout > 0)
+ {
+ co_await sdbusplus::async::sleep_for(ctx,
+ std::chrono::milliseconds(50));
+ try
+ {
+ debug("Test: querying new version");
+ newVersion = co_await clientNewVersion.version();
+ break;
+ }
+ catch (std::exception& _)
+ {
+ timeout -= 50;
+ }
+ }
+
+ EXPECT_EQ(timeout > 0, expectNewVersion);
+
+ // assert that update function was called
+ EXPECT_EQ(device->deviceSpecificUpdateFunctionCalled, expectNewVersion);
+
+ if (expectNewVersion)
+ {
+ EXPECT_EQ(newVersion, exampleVersion);
+ EXPECT_EQ(device->softwareCurrent->swid, objPathNewSoftware.filename());
+ }
+
+ ctx.request_stop();
+
+ co_return;
+}
+
+static int makeUpdateFd(const std::string& compatible,
+ const uint32_t vendorIANA, bool corrupted)
+{
+ int fd = memfd_create("test_memfd", 0);
+ EXPECT_GE(fd, 0);
+
+ if (fd < 0)
+ {
+ return fd;
+ }
+
+ debug("create fd {FD}", "FD", fd);
+
+ uint8_t component_image[] = {0x12, 0x34, 0x83, 0x21};
+
+ size_t size_out = 0;
+ std::unique_ptr<uint8_t[]> buf = create_pldm_package_buffer(
+ component_image, sizeof(component_image),
+ std::optional<uint32_t>(vendorIANA),
+ std::optional<std::string>(compatible), size_out);
+
+ if (corrupted)
+ {
+ buf[3] = 0x8;
+ buf[9] = 0x3;
+ }
+
+ ssize_t bytes_written = write(fd, (void*)buf.get(), size_out);
+ EXPECT_NE(bytes_written, -1)
+ << "Failed to write to memfd: " << strerror(errno);
+ if (bytes_written == -1)
+ {
+ close(fd);
+ return -1;
+ }
+
+ EXPECT_EQ(lseek(fd, 0, SEEK_SET), 0)
+ << "could not seek to the beginning of the file";
+ return fd;
+}
+
+void testcaseSoftwareUpdateCommon(const int fd, bool expectSuccess)
+{
+ ASSERT_GE(fd, 0);
+
+ sdbusplus::async::context ctx;
+
+ ctx.spawn(testSoftwareUpdateCommon(ctx, fd, expectSuccess));
+
+ ctx.run();
+ close(fd);
+}
+
+TEST(SoftwareUpdate, TestSoftwareUpdateSuccess)
+{
+ const int fd =
+ makeUpdateFd(exampleCompatibleHardware, exampleVendorIANA, false);
+
+ testcaseSoftwareUpdateCommon(fd, true);
+}
+
+TEST(SoftwareUpdate, TestSoftwareUpdateFailureWrongCompatible)
+{
+ const int fd = makeUpdateFd("not_compatible", exampleVendorIANA, false);
+
+ testcaseSoftwareUpdateCommon(fd, false);
+}
+
+TEST(SoftwareUpdate, TestSoftwareUpdateFailureWrongVendorIANA)
+{
+ const int fd = makeUpdateFd(exampleCompatibleHardware, 0x03289, false);
+
+ testcaseSoftwareUpdateCommon(fd, false);
+}
+
+TEST(SoftwareUpdate, TestSoftwareUpdateFailureCorruptedPackage)
+{
+ const int fd =
+ makeUpdateFd(exampleCompatibleHardware, exampleVendorIANA, true);
+
+ testcaseSoftwareUpdateCommon(fd, false);
+}
diff --git a/test/create_package/component_image_info_area.cpp b/test/create_package/component_image_info_area.cpp
index 52c4cbd..822d8e2 100644
--- a/test/create_package/component_image_info_area.cpp
+++ b/test/create_package/component_image_info_area.cpp
@@ -1,3 +1,5 @@
+#include "create_pldm_fw_package.hpp"
+
#include <inttypes.h>
#include <unistd.h>
@@ -56,7 +58,7 @@
// ComponentVersionStringType
b[i++] = 0x1; // type = Ascii
- const char* buf = (const char*)"mycompversion";
+ const char* buf = exampleVersion;
// ComponentVersionStringLength
b[i++] = strlen(buf);
diff --git a/test/create_package/create_pldm_fw_package.hpp b/test/create_package/create_pldm_fw_package.hpp
index 5d037c1..85d0676 100644
--- a/test/create_package/create_pldm_fw_package.hpp
+++ b/test/create_package/create_pldm_fw_package.hpp
@@ -6,6 +6,8 @@
#include <optional>
#include <string>
+constexpr const char* exampleVersion = "mycompversion";
+
std::optional<std::string> create_pldm_package(uint8_t* component_image,
size_t component_image_size);