mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-25 22:40:50 +00:00

This allows us to override the location we load data files from, which allows us to do more kinds of installed tests in the future. Also, move the global data/tests content into the place that it is used as it was getting impossible to manage.
398 lines
12 KiB
C
398 lines
12 KiB
C
/*
|
|
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <fwupd.h>
|
|
|
|
#include "fu-context-private.h"
|
|
#include "fu-device-private.h"
|
|
#ifdef HAVE_LINUX_IPMI_H
|
|
#include "fu-ipmi-device.h"
|
|
#endif
|
|
#include "fu-plugin-private.h"
|
|
#include "fu-redfish-common.h"
|
|
#include "fu-redfish-network.h"
|
|
|
|
typedef struct {
|
|
FuPlugin *plugin;
|
|
} FuTest;
|
|
|
|
static gboolean
|
|
fu_test_is_installed_test(void)
|
|
{
|
|
const gchar *builddir = g_getenv("G_TEST_BUILDDIR");
|
|
if (builddir == NULL)
|
|
return FALSE;
|
|
return g_str_has_prefix(builddir, "/usr");
|
|
}
|
|
|
|
static void
|
|
fu_test_self_init(FuTest *self)
|
|
{
|
|
gboolean ret;
|
|
g_autoptr(FuContext) ctx = fu_context_new();
|
|
g_autoptr(GError) error = NULL;
|
|
g_autofree gchar *pluginfn = NULL;
|
|
|
|
ret = fu_context_load_quirks(ctx,
|
|
FU_QUIRKS_LOAD_FLAG_NO_CACHE | FU_QUIRKS_LOAD_FLAG_NO_VERIFY,
|
|
&error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
|
|
self->plugin = fu_plugin_new(ctx);
|
|
|
|
/* running as an installed test */
|
|
if (fu_test_is_installed_test()) {
|
|
g_autofree gchar *plugindir = fu_common_get_path(FU_PATH_KIND_PLUGINDIR_PKG);
|
|
pluginfn =
|
|
g_build_filename(plugindir, "libfu_plugin_redfish." G_MODULE_SUFFIX, NULL);
|
|
} else {
|
|
pluginfn = g_test_build_filename(G_TEST_BUILT,
|
|
"libfu_plugin_redfish." G_MODULE_SUFFIX,
|
|
NULL);
|
|
}
|
|
ret = fu_plugin_open(self->plugin, pluginfn, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
ret = fu_plugin_runner_startup(self->plugin, &error);
|
|
if (g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE)) {
|
|
g_test_skip("no redfish.py running");
|
|
return;
|
|
}
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
ret = fu_plugin_runner_coldplug(self->plugin, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
}
|
|
|
|
static void
|
|
fu_test_redfish_ipmi_func(void)
|
|
{
|
|
#ifdef HAVE_LINUX_IPMI_H
|
|
gboolean ret;
|
|
g_autoptr(FuIpmiDevice) device = fu_ipmi_device_new(NULL);
|
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autofree gchar *username = NULL;
|
|
g_autofree gchar *str = NULL;
|
|
|
|
/* sanity check */
|
|
if (!g_file_test("/dev/ipmi0", G_FILE_TEST_EXISTS)) {
|
|
g_test_skip("no IPMI hardware");
|
|
return;
|
|
}
|
|
|
|
/* create device */
|
|
locker = fu_device_locker_new(device, &error);
|
|
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) {
|
|
g_test_skip("permission denied for access to IPMI hardware");
|
|
return;
|
|
}
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(locker);
|
|
str = fu_device_to_string(FU_DEVICE(device));
|
|
g_debug("%s", str);
|
|
|
|
/* add user that can do redfish commands */
|
|
if (g_getenv("FWUPD_REDFISH_SELF_TEST") == NULL) {
|
|
g_test_skip("not doing destructive tests");
|
|
return;
|
|
}
|
|
ret = fu_ipmi_device_set_user_name(device, 0x04, "fwupd", &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
username = fu_ipmi_device_get_user_password(device, 0x04, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(username);
|
|
g_debug("username=%s", username);
|
|
ret = fu_ipmi_device_set_user_enable(device, 0x04, TRUE, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
ret = fu_ipmi_device_set_user_priv(device, 0x04, 0x4, 1, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
ret = fu_ipmi_device_set_user_password(device, 0x04, "Passw0rd123", &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
#else
|
|
g_test_skip("no linux/ipmi.h, so skipping");
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
fu_test_redfish_common_func(void)
|
|
{
|
|
const guint8 buf[16] = {0x00,
|
|
0x01,
|
|
0x02,
|
|
0x03,
|
|
0x04,
|
|
0x05,
|
|
0x06,
|
|
0x07,
|
|
0x08,
|
|
0x09,
|
|
0x0a,
|
|
0x0b,
|
|
0x0c,
|
|
0x0d,
|
|
0x0e,
|
|
0x0f};
|
|
g_autofree gchar *ipv4 = NULL;
|
|
g_autofree gchar *ipv6 = NULL;
|
|
g_autofree gchar *maca = NULL;
|
|
|
|
ipv4 = fu_redfish_common_buffer_to_ipv4(buf);
|
|
g_assert_cmpstr(ipv4, ==, "0.1.2.3");
|
|
ipv6 = fu_redfish_common_buffer_to_ipv6(buf);
|
|
g_assert_cmpstr(ipv6, ==, "00010203:04050607:08090a0b:0c0d0e0f");
|
|
maca = fu_redfish_common_buffer_to_mac(buf);
|
|
g_assert_cmpstr(maca, ==, "00:01:02:03:04:05");
|
|
}
|
|
|
|
static void
|
|
fu_test_redfish_common_version_func(void)
|
|
{
|
|
struct {
|
|
const gchar *in;
|
|
const gchar *op;
|
|
} strs[] = {{"1.2.3", "1.2.3"},
|
|
{"P50 v1.2.3 PROD", "1.2.3"},
|
|
{"P50 1.2.3 DEV", "1.2.3"},
|
|
{NULL, NULL}};
|
|
for (guint i = 0; strs[i].in != NULL; i++) {
|
|
g_autofree gchar *tmp = fu_redfish_common_fix_version(strs[i].in);
|
|
g_assert_cmpstr(tmp, ==, strs[i].op);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fu_test_redfish_common_lenovo_func(void)
|
|
{
|
|
struct {
|
|
const gchar *in;
|
|
gboolean ret;
|
|
const gchar *build;
|
|
const gchar *version;
|
|
} values[] = {{"11A-1.02", TRUE, "11A", "1.02"},
|
|
{"11A-0.00", TRUE, "11A", "0.00"},
|
|
{"99Z-9.99", TRUE, "99Z", "9.99"},
|
|
{"9-9-9.99", FALSE, NULL, NULL},
|
|
{"999-9.99", FALSE, NULL, NULL},
|
|
{"ACB-9.99", FALSE, NULL, NULL},
|
|
{NULL, FALSE, NULL, NULL}};
|
|
for (guint i = 0; values[i].in != NULL; i++) {
|
|
gboolean ret;
|
|
g_autofree gchar *build = NULL;
|
|
g_autofree gchar *version = NULL;
|
|
ret = fu_redfish_common_parse_version_lenovo(values[i].in, &build, &version, NULL);
|
|
g_assert_cmpint(ret, ==, values[i].ret);
|
|
g_assert_cmpstr(build, ==, values[i].build);
|
|
g_assert_cmpstr(version, ==, values[i].version);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fu_test_redfish_network_mac_addr_func(void)
|
|
{
|
|
FuRedfishNetworkDeviceState state = FU_REDFISH_NETWORK_DEVICE_STATE_UNKNOWN;
|
|
gboolean ret;
|
|
g_autofree gchar *ip_addr = NULL;
|
|
g_autoptr(FuRedfishNetworkDevice) device = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
device = fu_redfish_network_device_for_mac_addr("00:13:F7:29:C2:D8", &error);
|
|
if (device == NULL && g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) {
|
|
g_test_skip("no hardware");
|
|
return;
|
|
}
|
|
if (device == NULL && g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
|
|
g_autofree gchar *str = g_strdup_printf("not supported: %s", error->message);
|
|
g_test_skip(str);
|
|
return;
|
|
}
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(device);
|
|
ret = fu_redfish_network_device_get_state(device, &state, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
if (state == FU_REDFISH_NETWORK_DEVICE_STATE_DISCONNECTED) {
|
|
ret = fu_redfish_network_device_connect(device, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
}
|
|
ip_addr = fu_redfish_network_device_get_address(device, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(ip_addr);
|
|
}
|
|
|
|
static void
|
|
fu_test_redfish_network_vid_pid_func(void)
|
|
{
|
|
g_autofree gchar *ip_addr = NULL;
|
|
g_autoptr(FuRedfishNetworkDevice) device = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
device = fu_redfish_network_device_for_vid_pid(0x0707, 0x0201, &error);
|
|
if (device == NULL && g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) {
|
|
g_test_skip("no hardware");
|
|
return;
|
|
}
|
|
if (device == NULL && g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
|
|
g_autofree gchar *str = g_strdup_printf("not supported: %s", error->message);
|
|
g_test_skip(str);
|
|
return;
|
|
}
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(device);
|
|
ip_addr = fu_redfish_network_device_get_address(device, &error);
|
|
g_assert_no_error(error);
|
|
g_assert_nonnull(ip_addr);
|
|
}
|
|
|
|
static void
|
|
fu_test_redfish_devices_func(gconstpointer user_data)
|
|
{
|
|
FuDevice *dev;
|
|
FuTest *self = (FuTest *)user_data;
|
|
GPtrArray *devices;
|
|
g_autofree gchar *devstr0 = NULL;
|
|
g_autofree gchar *devstr1 = NULL;
|
|
|
|
devices = fu_plugin_get_devices(self->plugin);
|
|
g_assert_nonnull(devices);
|
|
if (devices->len == 0) {
|
|
g_test_skip("no redfish support");
|
|
return;
|
|
}
|
|
g_assert_cmpint(devices->len, ==, 2);
|
|
|
|
/* BMC */
|
|
dev = g_ptr_array_index(devices, 1);
|
|
devstr0 = fu_device_to_string(dev);
|
|
g_debug("%s", devstr0);
|
|
g_assert_cmpstr(fu_device_get_id(dev), ==, "62c1cd95692c5225826cf8568a460427ea3b1827");
|
|
g_assert_cmpstr(fu_device_get_name(dev), ==, "BMC Firmware");
|
|
g_assert_cmpstr(fu_device_get_vendor(dev), ==, "Lenovo");
|
|
g_assert_cmpstr(fu_device_get_version(dev), ==, "1.02");
|
|
g_assert_cmpstr(fu_device_get_version_lowest(dev), ==, "0.12");
|
|
g_assert_cmpint(fu_device_get_version_format(dev), ==, FWUPD_VERSION_FORMAT_PAIR);
|
|
g_assert_cmpint(fu_device_get_version_build_date(dev), ==, 1552608000);
|
|
g_assert_true(fu_device_has_flag(dev, FWUPD_DEVICE_FLAG_UPDATABLE));
|
|
g_assert_true(fu_device_has_protocol(dev, "org.dmtf.redfish"));
|
|
g_assert_true(
|
|
fu_device_has_guid(dev, "REDFISH\\VENDOR_Lenovo&SOFTWAREID_UEFI-AFE1-6&TYPE_UNSIGNED"));
|
|
g_assert_true(fu_device_has_vendor_id(dev, "REDFISH:LENOVO"));
|
|
|
|
/* BIOS */
|
|
dev = g_ptr_array_index(devices, 0);
|
|
devstr1 = fu_device_to_string(dev);
|
|
g_debug("%s", devstr1);
|
|
g_assert_cmpstr(fu_device_get_id(dev), ==, "562313e34c756a05a2e878861377765582bbf971");
|
|
g_assert_cmpstr(fu_device_get_name(dev), ==, "BIOS Firmware");
|
|
g_assert_cmpstr(fu_device_get_vendor(dev), ==, "Contoso");
|
|
g_assert_cmpstr(fu_device_get_version(dev), ==, "1.45");
|
|
g_assert_cmpstr(fu_device_get_serial(dev), ==, "12345");
|
|
g_assert_cmpstr(fu_device_get_version_lowest(dev), ==, "1.10");
|
|
g_assert_cmpint(fu_device_get_version_format(dev), ==, FWUPD_VERSION_FORMAT_PAIR);
|
|
g_assert_cmpint(fu_device_get_version_build_date(dev), ==, 1552608000);
|
|
g_assert_true(fu_device_has_flag(dev, FWUPD_DEVICE_FLAG_UPDATABLE));
|
|
g_assert_true(fu_device_has_icon(dev, "network-wired"));
|
|
g_assert_true(fu_device_has_protocol(dev, "org.dmtf.redfish"));
|
|
g_assert_true(fu_device_has_guid(dev, "fee82a67-6ce2-4625-9f44-237ad2402c28"));
|
|
g_assert_true(fu_device_has_guid(dev, "a6d3294e-37e5-50aa-ae2f-c0c457af16f3"));
|
|
g_assert_true(fu_device_has_vendor_id(dev, "REDFISH:CONTOSO"));
|
|
}
|
|
|
|
static void
|
|
fu_test_redfish_update_func(gconstpointer user_data)
|
|
{
|
|
FuDevice *dev;
|
|
FuTest *self = (FuTest *)user_data;
|
|
GPtrArray *devices;
|
|
gboolean ret;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(GBytes) blob_fw = NULL;
|
|
g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
|
|
|
|
devices = fu_plugin_get_devices(self->plugin);
|
|
g_assert_nonnull(devices);
|
|
if (devices->len == 0) {
|
|
g_test_skip("no redfish support");
|
|
return;
|
|
}
|
|
g_assert_cmpint(devices->len, ==, 2);
|
|
|
|
/* BMC */
|
|
dev = g_ptr_array_index(devices, 1);
|
|
blob_fw = g_bytes_new_static("hello", 5);
|
|
ret = fu_plugin_runner_write_firmware(self->plugin,
|
|
dev,
|
|
blob_fw,
|
|
progress,
|
|
FWUPD_INSTALL_FLAG_NONE,
|
|
&error);
|
|
g_assert_no_error(error);
|
|
g_assert_true(ret);
|
|
g_assert_true(fu_device_has_flag(dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT));
|
|
|
|
/* try again */
|
|
ret = fu_plugin_runner_write_firmware(self->plugin,
|
|
dev,
|
|
blob_fw,
|
|
progress,
|
|
FWUPD_INSTALL_FLAG_NONE,
|
|
&error);
|
|
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_WRITE);
|
|
g_assert_false(ret);
|
|
}
|
|
|
|
static void
|
|
fu_test_self_free(FuTest *self)
|
|
{
|
|
if (self->plugin != NULL)
|
|
g_object_unref(self->plugin);
|
|
g_free(self);
|
|
}
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wunused-function"
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuTest, fu_test_self_free)
|
|
#pragma clang diagnostic pop
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
g_autoptr(FuTest) self = g_new0(FuTest, 1);
|
|
g_autofree gchar *smbios_data_fn = NULL;
|
|
g_autofree gchar *testdatadir = NULL;
|
|
|
|
g_test_init(&argc, &argv, NULL);
|
|
|
|
g_setenv("FWUPD_REDFISH_VERBOSE", "1", TRUE);
|
|
|
|
testdatadir = g_test_build_filename(G_TEST_DIST, "tests", NULL);
|
|
smbios_data_fn = g_build_filename(testdatadir, "redfish-smbios.bin", NULL);
|
|
g_setenv("FWUPD_REDFISH_SMBIOS_DATA", smbios_data_fn, TRUE);
|
|
g_setenv("FWUPD_SYSFSFWDIR", testdatadir, TRUE);
|
|
g_setenv("CONFIGURATION_DIRECTORY", testdatadir, TRUE);
|
|
|
|
g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
|
|
fu_test_self_init(self);
|
|
g_test_add_func("/redfish/ipmi", fu_test_redfish_ipmi_func);
|
|
g_test_add_func("/redfish/common", fu_test_redfish_common_func);
|
|
g_test_add_func("/redfish/common{version}", fu_test_redfish_common_version_func);
|
|
g_test_add_func("/redfish/common{lenovo}", fu_test_redfish_common_lenovo_func);
|
|
g_test_add_func("/redfish/network{mac_addr}", fu_test_redfish_network_mac_addr_func);
|
|
g_test_add_func("/redfish/network{vid_pid}", fu_test_redfish_network_vid_pid_func);
|
|
g_test_add_data_func("/redfish/plugin{devices}", self, fu_test_redfish_devices_func);
|
|
g_test_add_data_func("/redfish/plugin{update}", self, fu_test_redfish_update_func);
|
|
return g_test_run();
|
|
}
|