fwupd/src/fu-self-test.c
Richard Hughes 7afd7cba0d Use FuFirmware as a container for firmware images
In many plugins we've wanted to use ->prepare_firmware() to parse the firmware
ahead of ->detach() and ->write_firmware() but this has the limitation that it
can only return a single blob of data.

For many devices, multiple binary blobs are required from one parsed image,
for instance providing signatures, config and data blobs that have to be pushed
to the device in different way.

This also means we parse the firmware *before* we ask the user to detach.

Break the internal FuDevice API to support these firmware types as they become
more popular.

This also allows us to move the Intel HEX and SREC parsing out of the dfu plugin
as they are used by a few plugins now, and resolving symbols between plugins
isn't exactly awesome.
2019-08-08 13:10:57 +01:00

4008 lines
139 KiB
C

/*
* Copyright (C) 2015-2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <xmlb.h>
#include <fwupd.h>
#include <glib-object.h>
#include <glib/gstdio.h>
#include <gio/gfiledescriptorbased.h>
#include <libgcab.h>
#include <stdlib.h>
#include <string.h>
#include "fu-archive.h"
#include "fu-common-cab.h"
#include "fu-common-version.h"
#include "fu-chunk.h"
#include "fu-config.h"
#include "fu-device-list.h"
#include "fu-device-private.h"
#include "fu-engine.h"
#include "fu-ihex-firmware.h"
#include "fu-quirks.h"
#include "fu-keyring.h"
#include "fu-history.h"
#include "fu-install-task.h"
#include "fu-plugin-private.h"
#include "fu-plugin-list.h"
#include "fu-progressbar.h"
#include "fu-hash.h"
#include "fu-hwids.h"
#include "fu-smbios.h"
#include "fu-srec-firmware.h"
#include "fu-test.h"
#ifdef ENABLE_GPG
#include "fu-keyring-gpg.h"
#endif
#ifdef ENABLE_PKCS7
#include "fu-keyring-pkcs7.h"
#endif
static void
fu_self_test_mkroot (void)
{
if (g_file_test ("/tmp/fwupd-self-test", G_FILE_TEST_EXISTS)) {
g_autoptr(GError) error = NULL;
if (!fu_common_rmtree ("/tmp/fwupd-self-test", &error))
g_warning ("failed to mkroot: %s", error->message);
}
g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0);
}
static void
fu_archive_invalid_func (void)
{
g_autofree gchar *filename = NULL;
g_autoptr(FuArchive) archive = NULL;
g_autoptr(GBytes) data = NULL;
g_autoptr(GError) error = NULL;
filename = fu_test_get_filename (TESTDATADIR, "metadata.xml");
g_assert_nonnull (filename);
data = fu_common_get_contents_bytes (filename, &error);
g_assert_no_error (error);
g_assert_nonnull (data);
archive = fu_archive_new (data, FU_ARCHIVE_FLAG_NONE, &error);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
g_assert_null (archive);
}
static void
fu_engine_generate_md_func (void)
{
const gchar *tmp;
gboolean ret;
g_autofree gchar *filename = NULL;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(GBytes) data = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
/* put cab file somewhere we can parse it */
filename = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab");
g_assert_nonnull (filename);
data = fu_common_get_contents_bytes (filename, &error);
g_assert_no_error (error);
g_assert_nonnull (data);
ret = fu_common_set_contents_bytes ("/tmp/fwupd-self-test/var/cache/fwupd/foo.cab",
data, &error);
g_assert_no_error (error);
g_assert (ret);
/* load engine and check the device was found */
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
component = fu_engine_get_component_by_guids (engine, device);
g_assert_nonnull (component);
/* check remote ID set */
tmp = xb_node_query_text (component, "../custom/value[@key='fwupd::RemoteId']", NULL);
g_assert_cmpstr (tmp, ==, "directory");
/* verify checksums */
tmp = xb_node_query_text (component, "releases/release/checksum[@target='container']", NULL);
g_assert_cmpstr (tmp, !=, NULL);
tmp = xb_node_query_text (component, "releases/release/checksum[@target='content']", NULL);
g_assert_cmpstr (tmp, ==, NULL);
}
static void
fu_archive_cab_func (void)
{
g_autofree gchar *checksum1 = NULL;
g_autofree gchar *checksum2 = NULL;
g_autofree gchar *filename = NULL;
g_autoptr(FuArchive) archive = NULL;
g_autoptr(GBytes) data = NULL;
g_autoptr(GError) error = NULL;
GBytes *data_tmp;
filename = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab");
g_assert_nonnull (filename);
data = fu_common_get_contents_bytes (filename, &error);
g_assert_no_error (error);
g_assert_nonnull (data);
archive = fu_archive_new (data, FU_ARCHIVE_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert_nonnull (archive);
data_tmp = fu_archive_lookup_by_fn (archive, "firmware.metainfo.xml", &error);
g_assert_no_error (error);
g_assert_nonnull (data_tmp);
checksum1 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, data_tmp);
g_assert_cmpstr (checksum1, ==, "8611114f51f7151f190de86a5c9259d79ff34216");
data_tmp = fu_archive_lookup_by_fn (archive, "firmware.bin", &error);
g_assert_no_error (error);
g_assert_nonnull (data_tmp);
checksum2 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, data_tmp);
g_assert_cmpstr (checksum2, ==, "7c0ae84b191822bcadbdcbe2f74a011695d783c7");
data_tmp = fu_archive_lookup_by_fn (archive, "NOTGOINGTOEXIST.xml", &error);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
g_assert_null (data_tmp);
}
static void
fu_common_version_guess_format_func (void)
{
g_assert_cmpint (fu_common_version_guess_format (NULL), ==, FWUPD_VERSION_FORMAT_UNKNOWN);
g_assert_cmpint (fu_common_version_guess_format (""), ==, FWUPD_VERSION_FORMAT_UNKNOWN);
g_assert_cmpint (fu_common_version_guess_format ("1234ac"), ==, FWUPD_VERSION_FORMAT_PLAIN);
g_assert_cmpint (fu_common_version_guess_format ("1.2"), ==, FWUPD_VERSION_FORMAT_PAIR);
g_assert_cmpint (fu_common_version_guess_format ("1.2.3"), ==, FWUPD_VERSION_FORMAT_TRIPLET);
g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4"), ==, FWUPD_VERSION_FORMAT_QUAD);
g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4.5"), ==, FWUPD_VERSION_FORMAT_UNKNOWN);
g_assert_cmpint (fu_common_version_guess_format ("1a.2b.3"), ==, FWUPD_VERSION_FORMAT_PLAIN);
g_assert_cmpint (fu_common_version_guess_format ("1"), ==, FWUPD_VERSION_FORMAT_NUMBER);
g_assert_cmpint (fu_common_version_guess_format ("0x10201"), ==, FWUPD_VERSION_FORMAT_NUMBER);
}
static void
fu_engine_requirements_missing_func (void)
{
gboolean ret;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
const gchar *xml =
"<component>"
" <requires>"
" <id compare=\"ge\" version=\"1.2.3\">not.going.to.exist</id>"
" </requires>"
"</component>";
/* set up a dummy version */
fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3");
/* make the component require one thing */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this fails */
task = fu_install_task_new (NULL, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (!ret);
}
static void
fu_engine_requirements_unsupported_func (void)
{
gboolean ret;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
const gchar *xml =
"<component>"
" <requires>"
" <UNKNOWN compare=\"ge\" version=\"2.6.0\"/>"
" </requires>"
"</component>";
/* set up a dummy version */
fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3");
/* make the component require one thing that we don't support */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this fails */
task = fu_install_task_new (NULL, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert (!ret);
}
static void
fu_engine_requirements_child_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuDevice) child = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
const gchar *xml =
"<component>"
" <requires>"
" <firmware compare=\"eq\" version=\"0.0.1\">not-child</firmware>"
" </requires>"
" <provides>"
" <firmware type=\"flashed\">12345678-1234-1234-1234-123456789012</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.4\">"
" <checksum type=\"sha1\" filename=\"bios.bin\" target=\"content\"/>"
" </release>"
" </releases>"
"</component>";
/* set up a dummy device */
fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_version_bootloader (device, "4.5.6");
fu_device_set_vendor_id (device, "FFFF");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_set_version (child, "0.0.999", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_add_child (device, child);
/* make the component require three things */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this passes */
task = fu_install_task_new (device, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error (error);
g_assert (ret);
}
static void
fu_engine_requirements_child_fail_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuDevice) child = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
const gchar *xml =
"<component>"
" <requires>"
" <firmware compare=\"glob\" version=\"0.0.*\">not-child</firmware>"
" </requires>"
" <provides>"
" <firmware type=\"flashed\">12345678-1234-1234-1234-123456789012</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.4\">"
" <checksum type=\"sha1\" filename=\"bios.bin\" target=\"content\"/>"
" </release>"
" </releases>"
"</component>";
/* set up a dummy device */
fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_version_bootloader (device, "4.5.6");
fu_device_set_vendor_id (device, "FFFF");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_set_version (child, "0.0.1", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_add_child (device, child);
/* make the component require three things */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this passes */
task = fu_install_task_new (device, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_nonnull (g_strstr_len (error->message, -1,
"Not compatible with child device version"));
g_assert (!ret);
}
static void
fu_engine_requirements_func (void)
{
gboolean ret;
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
const gchar *xml =
"<component>"
" <requires>"
" <id compare=\"ge\" version=\"1.2.3\">org.test.dummy</id>"
" </requires>"
"</component>";
/* set up some dummy versions */
fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3");
fu_engine_add_runtime_version (engine, "com.hughski.colorhug", "7.8.9");
/* make the component require one thing */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this passes */
task = fu_install_task_new (NULL, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error (error);
g_assert (ret);
}
static void
fu_engine_requirements_device_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
const gchar *xml =
"<component>"
" <requires>"
" <firmware compare=\"ge\" version=\"1.2.3\"/>"
" <firmware compare=\"eq\" version=\"4.5.6\">bootloader</firmware>"
" <firmware compare=\"eq\" version=\"FFFF\">vendor-id</firmware>"
" </requires>"
" <provides>"
" <firmware type=\"flashed\">12345678-1234-1234-1234-123456789012</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.4\">"
" <checksum type=\"sha1\" filename=\"bios.bin\" target=\"content\"/>"
" </release>"
" </releases>"
"</component>";
/* set up a dummy device */
fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_version_bootloader (device, "4.5.6");
fu_device_set_vendor_id (device, "FFFF");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
/* make the component require three things */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this passes */
task = fu_install_task_new (device, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error (error);
g_assert (ret);
}
static void
fu_engine_requirements_version_format_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
const gchar *xml =
"<component>"
" <provides>"
" <firmware type=\"flashed\">12345678-1234-1234-1234-123456789012</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.4\">"
" <checksum type=\"sha1\" filename=\"bios.bin\" target=\"content\"/>"
" </release>"
" </releases>"
" <custom>"
" <value key=\"LVFS::VersionFormat\">triplet</value>"
" </custom>"
"</component>";
/* set up a dummy device */
fu_device_set_version (device, "1.2.3.4", FWUPD_VERSION_FORMAT_QUAD);
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
/* make the component require three things */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this fails */
task = fu_install_task_new (device, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_nonnull (g_strstr_len (error->message, -1,
"Firmware version formats were different"));
g_assert (!ret);
}
static void
fu_engine_requirements_other_device_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
const gchar *xml =
"<component>"
" <requires>"
" <firmware compare=\"gt\" version=\"4.0.0\">1ff60ab2-3905-06a1-b476-0371f00c9e9b</firmware>"
" </requires>"
" <provides>"
" <firmware type=\"flashed\">12345678-1234-1234-1234-123456789012</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.4\">"
" <checksum type=\"sha1\" filename=\"bios.bin\" target=\"content\"/>"
" </release>"
" </releases>"
"</component>";
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* set up a dummy device */
fu_device_set_version (device1, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_guid (device1, "12345678-1234-1234-1234-123456789012");
/* set up a different device */
fu_device_set_id (device2, "id2");
fu_device_set_name (device2, "Secondary firmware");
fu_device_set_version (device2, "4.5.6", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_vendor_id (device2, "FFFF");
fu_device_add_guid (device2, "1ff60ab2-3905-06a1-b476-0371f00c9e9b");
fu_engine_add_device (engine, device2);
/* import firmware metainfo */
silo = xb_silo_new_from_xml (xml, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "component", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check this passes */
task = fu_install_task_new (device1, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error (error);
g_assert (ret);
}
static void
fu_engine_device_priority_func (void)
{
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(FuDevice) device3 = fu_device_new ();
g_autoptr(FuDevice) device = NULL;
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(GError) error = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* add low prio then high then low */
fu_device_set_id (device1, "id1");
fu_device_set_priority (device1, 0);
fu_device_set_plugin (device1, "udev");
fu_device_add_instance_id (device1, "GUID1");
fu_device_convert_instance_ids (device1);
fu_engine_add_device (engine, device1);
fu_device_set_id (device2, "id2");
fu_device_set_priority (device2, 1);
fu_device_set_plugin (device2, "redfish");
fu_device_add_instance_id (device2, "GUID1");
fu_device_convert_instance_ids (device2);
fu_engine_add_device (engine, device2);
fu_device_set_id (device3, "id3");
fu_device_set_priority (device3, 0);
fu_device_set_plugin (device3, "uefi");
fu_device_add_instance_id (device3, "GUID1");
fu_device_convert_instance_ids (device3);
fu_engine_add_device (engine, device3);
/* get the high prio device */
device = fu_engine_get_device (engine, "867d5f8110f8aa79dd63d7440f21724264f10430", &error);
g_assert_no_error (error);
g_assert_cmpint (fu_device_get_priority (device), ==, 1);
g_clear_object (&device);
/* the now-removed low-prio device */
device = fu_engine_get_device (engine, "4e89d81a2e6fb4be2578d245fd8511c1f4ad0b58", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert_null (device);
g_clear_error (&error);
/* the never-added 2nd low-prio device */
device = fu_engine_get_device (engine, "c48feddbbcfee514f530ce8f7f2dccd98b6cc150", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert_null (device);
}
static void
fu_engine_device_parent_func (void)
{
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(FuDevice) device3 = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* add child */
fu_device_set_id (device1, "child");
fu_device_add_instance_id (device1, "child-GUID-1");
fu_device_add_parent_guid (device1, "parent-GUID");
fu_device_convert_instance_ids (device1);
fu_engine_add_device (engine, device1);
/* parent */
fu_device_set_id (device2, "parent");
fu_device_add_instance_id (device2, "parent-GUID");
fu_device_set_vendor (device2, "oem");
fu_device_convert_instance_ids (device2);
/* add another child */
fu_device_set_id (device3, "child2");
fu_device_add_instance_id (device3, "child-GUID-2");
fu_device_add_parent_guid (device3, "parent-GUID");
fu_device_convert_instance_ids (device3);
fu_device_add_child (device2, device3);
/* add two together */
fu_engine_add_device (engine, device2);
/* verify both children were adopted */
g_assert (fu_device_get_parent (device3) == device2);
g_assert (fu_device_get_parent (device1) == device2);
g_assert_cmpstr (fu_device_get_vendor (device3), ==, "oem");
g_assert_cmpstr (fu_device_get_vendor (device1), ==, "oem");
/* verify order */
g_assert_cmpint (fu_device_get_order (device1), ==, 0);
g_assert_cmpint (fu_device_get_order (device2), ==, 1);
g_assert_cmpint (fu_device_get_order (device3), ==, 0);
}
static void
fu_engine_partial_hash_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuPlugin) plugin = fu_plugin_new ();
g_autoptr(GError) error = NULL;
g_autoptr(GError) error_none = NULL;
g_autoptr(GError) error_both = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* set up dummy plugin */
fu_plugin_set_name (plugin, "test");
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
fu_engine_add_plugin (engine, plugin);
/* add two dummy devices */
fu_device_set_id (device1, "device1");
fu_device_set_plugin (device1, "test");
fu_device_add_guid (device1, "12345678-1234-1234-1234-123456789012");
fu_engine_add_device (engine, device1);
fu_device_set_id (device2, "device21");
fu_device_set_plugin (device2, "test");
fu_device_set_equivalent_id (device2, "b92f5b7560b84ca005a79f5a15de3c003ce494cf");
fu_device_add_guid (device2, "12345678-1234-1234-1234-123456789012");
fu_engine_add_device (engine, device2);
/* match nothing */
ret = fu_engine_unlock (engine, "deadbeef", &error_none);
g_assert_error (error_none, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (!ret);
/* match both */
ret = fu_engine_unlock (engine, "9", &error_both);
g_assert_error (error_both, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert (!ret);
/* match one exactly */
fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_LOCKED);
fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_LOCKED);
ret = fu_engine_unlock (engine, "934b4162a6daa0b033d649c8d464529cec41d3de", &error);
g_assert_no_error (error);
g_assert (ret);
/* match one partially */
fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_LOCKED);
fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_LOCKED);
ret = fu_engine_unlock (engine, "934b", &error);
g_assert_no_error (error);
g_assert (ret);
/* match equivalent ID */
fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_LOCKED);
fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_LOCKED);
ret = fu_engine_unlock (engine, "b92f", &error);
g_assert_no_error (error);
g_assert (ret);
}
static void
fu_engine_device_unlock_func (void)
{
gboolean ret;
g_autofree gchar *filename = NULL;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(GError) error = NULL;
g_autoptr(GFile) file = NULL;
g_autoptr(XbBuilder) builder = xb_builder_new ();
g_autoptr(XbBuilderSource) source = xb_builder_source_new ();
g_autoptr(XbSilo) silo = NULL;
/* load engine to get FuConfig set up */
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
/* add the hardcoded 'fwupd' metadata */
filename = fu_test_get_filename (TESTDATADIR, "metadata.xml");
g_assert (filename != NULL);
file = g_file_new_for_path (filename);
ret = xb_builder_source_load_file (source, file,
XB_BUILDER_SOURCE_FLAG_NONE,
NULL, &error);
g_assert_no_error (error);
g_assert_true (ret);
xb_builder_import_source (builder, source);
silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
fu_engine_set_silo (engine, silo);
/* add a dummy device */
fu_device_set_id (device, "UEFI-dummy-dev0");
fu_device_add_guid (device, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_LOCKED);
fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_PLAIN);
fu_engine_add_device (engine, device);
/* ensure the metainfo was matched */
g_assert_nonnull (fwupd_device_get_release_default (FWUPD_DEVICE (device)));
}
static void
fu_engine_require_hwid_func (void)
{
gboolean ret;
g_autofree gchar *filename = NULL;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
g_autoptr(XbSilo) silo = NULL;
#if !defined(HAVE_GCAB_0_8) && defined(__s390x__)
/* See https://github.com/hughsie/fwupd/issues/318 for more information */
g_test_skip ("Skipping HWID test on s390x due to known problem with gcab");
return;
#endif
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* load engine to get FuConfig set up */
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
/* get generated file as a blob */
filename = fu_test_get_filename (TESTDATADIR, "missing-hwid/hwid-1.2.3.cab");
g_assert (filename != NULL);
blob_cab = fu_common_get_contents_bytes (filename, &error);
g_assert_no_error (error);
g_assert (blob_cab != NULL);
silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
/* add a dummy device */
fu_device_set_id (device, "test_device");
fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_engine_add_device (engine, device);
/* get component */
component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* check requirements */
task = fu_install_task_new (device, component);
ret = fu_engine_check_requirements (engine, task,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert (error != NULL);
g_assert_cmpstr (error->message, ==,
"no HWIDs matched 9342d47a-1bab-5709-9869-c840b2eac501");
g_assert (!ret);
}
static void
fu_engine_downgrade_func (void)
{
FwupdRelease *rel;
gboolean ret;
g_autofree gchar *testdatadir = NULL;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GPtrArray) devices_pre = NULL;
g_autoptr(GPtrArray) releases_dg = NULL;
g_autoptr(GPtrArray) releases = NULL;
g_autoptr(GPtrArray) releases_up = NULL;
g_autoptr(GPtrArray) remotes = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
/* ensure empty tree */
fu_self_test_mkroot ();
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* write a broken file */
ret = g_file_set_contents ("/tmp/fwupd-self-test/broken.xml.gz",
"this is not a valid", -1, &error);
g_assert_no_error (error);
g_assert (ret);
/* write the main file */
ret = g_file_set_contents ("/tmp/fwupd-self-test/stable.xml",
"<components>"
" <component type=\"firmware\">"
" <id>test</id>"
" <name>Test Device</name>"
" <provides>"
" <firmware type=\"flashed\">aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.3\" date=\"2017-09-15\">"
" <size type=\"installed\">123</size>"
" <size type=\"download\">456</size>"
" <location>https://test.org/foo.cab</location>"
" <checksum filename=\"foo.cab\" target=\"container\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" </release>"
" <release version=\"1.2.2\" date=\"2017-09-01\">"
" <size type=\"installed\">123</size>"
" <size type=\"download\">456</size>"
" <location>https://test.org/foo.cab</location>"
" <checksum filename=\"foo.cab\" target=\"container\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" </release>"
" </releases>"
" </component>"
"</components>", -1, &error);
g_assert_no_error (error);
g_assert (ret);
/* write the extra file */
ret = g_file_set_contents ("/tmp/fwupd-self-test/testing.xml",
"<components>"
" <component type=\"firmware\">"
" <id>test</id>"
" <name>Test Device</name>"
" <provides>"
" <firmware type=\"flashed\">aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.5\" date=\"2017-09-16\">"
" <size type=\"installed\">123</size>"
" <size type=\"download\">456</size>"
" <location>https://test.org/foo.cab</location>"
" <checksum filename=\"foo.cab\" target=\"container\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" </release>"
" <release version=\"1.2.4\" date=\"2017-09-15\">"
" <size type=\"installed\">123</size>"
" <size type=\"download\">456</size>"
" <location>https://test.org/foo.cab</location>"
" <checksum filename=\"foo.cab\" target=\"container\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" </release>"
" </releases>"
" </component>"
"</components>", -1, &error);
g_assert_no_error (error);
g_assert (ret);
testdatadir = fu_test_get_filename (TESTDATADIR, ".");
g_assert (testdatadir != NULL);
g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE);
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (fu_engine_get_status (engine), ==, FWUPD_STATUS_IDLE);
g_test_assert_expected_messages ();
/* return all the remotes, even the broken one */
remotes = fu_engine_get_remotes (engine, &error);
g_assert_no_error (error);
g_assert (remotes != NULL);
g_assert_cmpint (remotes->len, ==, 4);
/* ensure there are no devices already */
devices_pre = fu_engine_get_devices (engine, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO);
g_assert (devices_pre == NULL);
g_clear_error (&error);
/* add a device so we can get upgrades and downgrades */
fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_id (device, "test_device");
fu_device_set_name (device, "Test Device");
fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_engine_add_device (engine, device);
devices = fu_engine_get_devices (engine, &error);
g_assert_no_error (error);
g_assert (devices != NULL);
g_assert_cmpint (devices->len, ==, 1);
g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED));
g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED));
/* get the releases for one device */
releases = fu_engine_get_releases (engine, fu_device_get_id (device), &error);
g_assert_no_error (error);
g_assert (releases != NULL);
g_assert_cmpint (releases->len, ==, 4);
/* no upgrades, as no firmware is approved */
releases_up = fu_engine_get_upgrades (engine, fu_device_get_id (device), &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO);
g_assert_null (releases_up);
g_clear_error (&error);
/* retry with approved firmware set */
fu_engine_add_approved_firmware (engine, "deadbeefdeadbeefdeadbeefdeadbeef");
fu_engine_add_approved_firmware (engine, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
/* upgrades */
releases_up = fu_engine_get_upgrades (engine, fu_device_get_id (device), &error);
g_assert_no_error (error);
g_assert (releases_up != NULL);
g_assert_cmpint (releases_up->len, ==, 2);
/* ensure the list is sorted */
rel = FWUPD_RELEASE (g_ptr_array_index (releases_up, 0));
g_assert_cmpstr (fwupd_release_get_version (rel), ==, "1.2.5");
rel = FWUPD_RELEASE (g_ptr_array_index (releases_up, 1));
g_assert_cmpstr (fwupd_release_get_version (rel), ==, "1.2.4");
/* downgrades */
releases_dg = fu_engine_get_downgrades (engine, fu_device_get_id (device), &error);
g_assert_no_error (error);
g_assert (releases_dg != NULL);
g_assert_cmpint (releases_dg->len, ==, 1);
rel = FWUPD_RELEASE (g_ptr_array_index (releases_dg, 0));
g_assert_cmpstr (fwupd_release_get_version (rel), ==, "1.2.2");
}
static void
fu_engine_install_duration_func (void)
{
FwupdRelease *rel;
gboolean ret;
g_autofree gchar *testdatadir = NULL;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GPtrArray) releases = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
/* ensure empty tree */
fu_self_test_mkroot ();
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* write the main file */
ret = g_file_set_contents ("/tmp/fwupd-self-test/stable.xml",
"<components>"
" <component type=\"firmware\">"
" <id>test</id>"
" <provides>"
" <firmware type=\"flashed\">aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.3\" date=\"2017-09-15\" install_duration=\"120\">"
" <location>https://test.org/foo.cab</location>"
" <checksum filename=\"foo.cab\" target=\"container\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"md5\">deadbeefdeadbeefdeadbeefdeadbeef</checksum>"
" </release>"
" </releases>"
" </component>"
"</components>", -1, &error);
g_assert_no_error (error);
g_assert (ret);
testdatadir = fu_test_get_filename (TESTDATADIR, ".");
g_assert (testdatadir != NULL);
g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE);
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
/* add a device so we can get the install duration */
fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_id (device, "test_device");
fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee");
fu_device_set_install_duration (device, 999);
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_engine_add_device (engine, device);
devices = fu_engine_get_devices (engine, &error);
g_assert_no_error (error);
g_assert (devices != NULL);
g_assert_cmpint (devices->len, ==, 1);
g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED));
/* check the release install duration */
releases = fu_engine_get_releases (engine, fu_device_get_id (device), &error);
g_assert_no_error (error);
g_assert (releases != NULL);
g_assert_cmpint (releases->len, ==, 1);
rel = FWUPD_RELEASE (g_ptr_array_index (releases, 0));
g_assert_cmpint (fwupd_release_get_install_duration (rel), ==, 120);
}
static void
fu_engine_history_func (void)
{
gboolean ret;
g_autofree gchar *checksum = NULL;
g_autofree gchar *device_str_expected = NULL;
g_autofree gchar *device_str = NULL;
g_autofree gchar *filename = NULL;
g_autofree gchar *testdatadir = NULL;
g_autoptr(FuDevice) device2 = NULL;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuHistory) history = NULL;
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuPlugin) plugin = fu_plugin_new ();
g_autoptr(FwupdDevice) device3 = NULL;
g_autoptr(FwupdDevice) device4 = NULL;
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
g_autoptr(XbSilo) silo = NULL;
/* ensure empty tree */
fu_self_test_mkroot ();
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* set up dummy plugin */
ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error);
g_assert_no_error (error);
g_assert (ret);
fu_engine_add_plugin (engine, plugin);
testdatadir = fu_test_get_filename (TESTDATADIR, ".");
g_assert (testdatadir != NULL);
g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE);
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (fu_engine_get_status (engine), ==, FWUPD_STATUS_IDLE);
/* add a device so we can get upgrade it */
fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_id (device, "test_device");
fu_device_set_name (device, "Test Device");
fu_device_set_plugin (device, "test");
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_add_checksum (device, "0123456789abcdef0123456789abcdef01234567");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_set_created (device, 1515338000);
fu_engine_add_device (engine, device);
devices = fu_engine_get_devices (engine, &error);
g_assert_no_error (error);
g_assert (devices != NULL);
g_assert_cmpint (devices->len, ==, 1);
g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED));
filename = fu_test_get_filename (TESTDATADIR, "missing-hwid/noreqs-1.2.3.cab");
g_assert (filename != NULL);
blob_cab = fu_common_get_contents_bytes (filename, &error);
g_assert_no_error (error);
g_assert (blob_cab != NULL);
silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
/* get component */
component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* set the counter */
g_setenv ("FWUPD_PLUGIN_TEST", "another-write-required", TRUE);
fu_device_set_metadata_integer (device, "nr-update", 0);
/* install it */
task = fu_install_task_new (device, component);
ret = fu_engine_install (engine, task, blob_cab,
FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
/* check the write was done more than once */
g_assert_cmpint (fu_device_get_metadata_integer (device, "nr-update"), ==, 2);
/* check the history database */
history = fu_history_new ();
device2 = fu_history_get_device_by_id (history, fu_device_get_id (device), &error);
g_assert_no_error (error);
g_assert (device2 != NULL);
g_assert_cmpint (fu_device_get_update_state (device2), ==, FWUPD_UPDATE_STATE_SUCCESS);
g_assert_cmpstr (fu_device_get_update_error (device2), ==, NULL);
fu_device_set_modified (device2, 1514338000);
g_hash_table_remove_all (fwupd_release_get_metadata (fu_device_get_release_default (device2)));
device_str = fu_device_to_string (device2);
checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob_cab);
device_str_expected = g_strdup_printf (
"Test Device\n"
" DeviceId: 894e8c17a29428b09d10cd90d1db74ea76fbcfe8\n"
" Guid: 12345678-1234-1234-1234-123456789012\n"
" Plugin: test\n"
" Flags: updatable\n"
" Version: 1.2.2\n"
" Created: 2018-01-07\n"
" Modified: 2017-12-27\n"
" UpdateState: success\n"
" \n"
" [Release]\n"
" Version: 1.2.3\n"
" Checksum: SHA1(%s)\n"
" Flags: none\n",
checksum);
ret = fu_test_compare_lines (device_str, device_str_expected, &error);
g_assert_no_error (error);
g_assert (ret);
/* GetResults() */
device3 = fu_engine_get_results (engine, FWUPD_DEVICE_ID_ANY, &error);
g_assert (device3 != NULL);
g_assert_cmpstr (fu_device_get_id (device3), ==,
"894e8c17a29428b09d10cd90d1db74ea76fbcfe8");
g_assert_cmpint (fu_device_get_update_state (device3), ==, FWUPD_UPDATE_STATE_SUCCESS);
g_assert_cmpstr (fu_device_get_update_error (device3), ==, NULL);
/* ClearResults() */
ret = fu_engine_clear_results (engine, FWUPD_DEVICE_ID_ANY, &error);
g_assert_no_error (error);
g_assert (ret);
/* GetResults() */
device4 = fu_engine_get_results (engine, FWUPD_DEVICE_ID_ANY, &error);
g_assert (device4 == NULL);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO);
}
static void
fu_engine_history_inherit (void)
{
gboolean ret;
g_autofree gchar *filename = NULL;
g_autofree gchar *testdatadir = NULL;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuPlugin) plugin = fu_plugin_new ();
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
g_autoptr(XbSilo) silo = NULL;
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* set up dummy plugin */
g_setenv ("FWUPD_PLUGIN_TEST", "fail", TRUE);
ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error);
g_assert_no_error (error);
g_assert (ret);
fu_engine_add_plugin (engine, plugin);
testdatadir = fu_test_get_filename (TESTDATADIR, ".");
g_assert (testdatadir != NULL);
g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE);
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (fu_engine_get_status (engine), ==, FWUPD_STATUS_IDLE);
/* add a device so we can get upgrade it */
fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_id (device, "test_device");
fu_device_set_name (device, "Test Device");
fu_device_set_plugin (device, "test");
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_set_created (device, 1515338000);
fu_engine_add_device (engine, device);
devices = fu_engine_get_devices (engine, &error);
g_assert_no_error (error);
g_assert (devices != NULL);
g_assert_cmpint (devices->len, ==, 1);
g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED));
filename = fu_test_get_filename (TESTDATADIR, "missing-hwid/noreqs-1.2.3.cab");
g_assert (filename != NULL);
blob_cab = fu_common_get_contents_bytes (filename, &error);
g_assert_no_error (error);
g_assert (blob_cab != NULL);
silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
/* get component */
component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
/* install it */
g_setenv ("FWUPD_PLUGIN_TEST", "requires-activation", TRUE);
task = fu_install_task_new (device, component);
ret = fu_engine_install (engine, task, blob_cab,
FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
/* check the device requires an activation */
g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION));
g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.2");
/* activate the device */
ret = fu_engine_activate (engine, fu_device_get_id (device), &error);
g_assert_no_error (error);
g_assert (ret);
/* check the device no longer requires an activation */
g_assert_false (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION));
g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3");
/* emulate getting the flag for a fresh boot on old firmware */
fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET);
ret = fu_engine_install (engine, task, blob_cab,
FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
g_object_unref (engine);
g_object_unref (device);
engine = fu_engine_new (FU_APP_FLAGS_NONE);
fu_engine_set_silo (engine, silo_empty);
fu_engine_add_plugin (engine, plugin);
device = fu_device_new ();
fu_device_set_id (device, "test_device");
fu_device_set_name (device, "Test Device");
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET);
fu_engine_add_device (engine, device);
g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION));
}
static void
fu_engine_history_error_func (void)
{
gboolean ret;
g_autofree gchar *checksum = NULL;
g_autofree gchar *device_str_expected = NULL;
g_autofree gchar *device_str = NULL;
g_autofree gchar *filename = NULL;
g_autofree gchar *testdatadir = NULL;
g_autoptr(FuDevice) device2 = NULL;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuHistory) history = NULL;
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuPlugin) plugin = fu_plugin_new ();
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error2 = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
g_autoptr(XbSilo) silo = NULL;
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* set up dummy plugin */
g_setenv ("FWUPD_PLUGIN_TEST", "fail", TRUE);
ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error);
g_assert_no_error (error);
g_assert (ret);
fu_engine_add_plugin (engine, plugin);
testdatadir = fu_test_get_filename (TESTDATADIR, ".");
g_assert (testdatadir != NULL);
g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE);
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (fu_engine_get_status (engine), ==, FWUPD_STATUS_IDLE);
/* add a device so we can get upgrade it */
fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_id (device, "test_device");
fu_device_set_name (device, "Test Device");
fu_device_set_plugin (device, "test");
fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012");
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_set_created (device, 1515338000);
fu_engine_add_device (engine, device);
devices = fu_engine_get_devices (engine, &error);
g_assert_no_error (error);
g_assert (devices != NULL);
g_assert_cmpint (devices->len, ==, 1);
g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED));
/* install the wrong thing */
filename = fu_test_get_filename (TESTDATADIR, "missing-hwid/noreqs-1.2.3.cab");
g_assert (filename != NULL);
blob_cab = fu_common_get_contents_bytes (filename, &error);
g_assert_no_error (error);
g_assert (blob_cab != NULL);
silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
task = fu_install_task_new (device, component);
ret = fu_engine_install (engine, task, blob_cab,
FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert (error != NULL);
g_assert_cmpstr (error->message, ==,
"device was not in supported mode");
g_assert (!ret);
/* check the history database */
history = fu_history_new ();
device2 = fu_history_get_device_by_id (history, fu_device_get_id (device), &error2);
g_assert_no_error (error2);
g_assert (device2 != NULL);
g_assert_cmpint (fu_device_get_update_state (device2), ==, FWUPD_UPDATE_STATE_FAILED);
g_assert_cmpstr (fu_device_get_update_error (device2), ==, error->message);
g_clear_error (&error);
fu_device_set_modified (device2, 1514338000);
g_hash_table_remove_all (fwupd_release_get_metadata (fu_device_get_release_default (device2)));
device_str = fu_device_to_string (device2);
checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob_cab);
device_str_expected = g_strdup_printf (
"Test Device\n"
" DeviceId: 894e8c17a29428b09d10cd90d1db74ea76fbcfe8\n"
" Guid: 12345678-1234-1234-1234-123456789012\n"
" Plugin: test\n"
" Flags: updatable\n"
" Version: 1.2.2\n"
" Created: 2018-01-07\n"
" Modified: 2017-12-27\n"
" UpdateState: failed\n"
" UpdateError: device was not in supported mode\n"
" \n"
" [Release]\n"
" Version: 1.2.3\n"
" Checksum: SHA1(%s)\n"
" Flags: none\n",
checksum);
ret = fu_test_compare_lines (device_str, device_str_expected, &error);
g_assert_no_error (error);
g_assert (ret);
}
static void
_device_list_count_cb (FuDeviceList *device_list, FuDevice *device, gpointer user_data)
{
guint *cnt = (guint *) user_data;
(*cnt)++;
}
static void
fu_device_list_delay_func (void)
{
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(FuDeviceList) device_list = fu_device_list_new ();
guint added_cnt = 0;
guint changed_cnt = 0;
guint removed_cnt = 0;
g_signal_connect (device_list, "added",
G_CALLBACK (_device_list_count_cb),
&added_cnt);
g_signal_connect (device_list, "removed",
G_CALLBACK (_device_list_count_cb),
&removed_cnt);
g_signal_connect (device_list, "changed",
G_CALLBACK (_device_list_count_cb),
&changed_cnt);
/* add one device */
fu_device_set_id (device1, "device1");
fu_device_add_instance_id (device1, "foobar");
fu_device_set_remove_delay (device1, 100);
fu_device_convert_instance_ids (device1);
fu_device_list_add (device_list, device1);
g_assert_cmpint (added_cnt, ==, 1);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 0);
/* add the same device again */
fu_device_list_add (device_list, device1);
g_assert_cmpint (added_cnt, ==, 1);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 0);
/* add a device with the same ID */
fu_device_set_id (device2, "device1");
fu_device_list_add (device_list, device2);
g_assert_cmpint (added_cnt, ==, 1);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 0);
/* spin a bit */
fu_test_loop_run_with_timeout (10);
fu_test_loop_quit ();
/* verify only a changed event was generated */
added_cnt = removed_cnt = changed_cnt = 0;
fu_device_list_remove (device_list, device1);
fu_device_list_add (device_list, device1);
g_assert_cmpint (added_cnt, ==, 0);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 1);
}
typedef struct {
FuDevice *device_new;
FuDevice *device_old;
FuDeviceList *device_list;
} FuDeviceListReplugHelper;
static gboolean
fu_device_list_remove_cb (gpointer user_data)
{
FuDeviceListReplugHelper *helper = (FuDeviceListReplugHelper *) user_data;
fu_device_list_remove (helper->device_list, helper->device_old);
return FALSE;
}
static gboolean
fu_device_list_add_cb (gpointer user_data)
{
FuDeviceListReplugHelper *helper = (FuDeviceListReplugHelper *) user_data;
fu_device_list_add (helper->device_list, helper->device_new);
return FALSE;
}
static void
fu_device_list_replug_auto_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(FuDevice) parent = fu_device_new ();
g_autoptr(FuDeviceList) device_list = fu_device_list_new ();
g_autoptr(GError) error = NULL;
FuDeviceListReplugHelper helper;
/* parent */
fu_device_set_id (parent, "parent");
/* fake child devices */
fu_device_set_id (device1, "device1");
fu_device_set_physical_id (device1, "ID");
fu_device_set_plugin (device1, "self-test");
fu_device_set_remove_delay (device1, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
fu_device_add_child (parent, device1);
fu_device_set_id (device2, "device2");
fu_device_set_physical_id (device2, "ID"); /* matches */
fu_device_set_plugin (device2, "self-test");
fu_device_set_remove_delay (device2, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE);
/* not yet added */
ret = fu_device_list_wait_for_replug (device_list, device1, &error);
g_assert_no_error (error);
g_assert (ret);
/* add device */
fu_device_list_add (device_list, device1);
/* not waiting */
ret = fu_device_list_wait_for_replug (device_list, device1, &error);
g_assert_no_error (error);
g_assert (ret);
/* waiting */
helper.device_old = device1;
helper.device_new = device2;
helper.device_list = device_list;
g_timeout_add (100, fu_device_list_remove_cb, &helper);
g_timeout_add (200, fu_device_list_add_cb, &helper);
fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
ret = fu_device_list_wait_for_replug (device_list, device1, &error);
g_assert_no_error (error);
g_assert (ret);
/* check device2 now has parent too */
g_assert (fu_device_get_parent (device2) == parent);
/* waiting, failed */
fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
ret = fu_device_list_wait_for_replug (device_list, device2, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (!ret);
}
static void
fu_device_list_replug_user_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(FuDeviceList) device_list = fu_device_list_new ();
g_autoptr(GError) error = NULL;
FuDeviceListReplugHelper helper;
/* fake devices */
fu_device_set_id (device1, "device1");
fu_device_add_instance_id (device1, "foo");
fu_device_add_instance_id (device1, "bar");
fu_device_set_plugin (device1, "self-test");
fu_device_set_remove_delay (device1, FU_DEVICE_REMOVE_DELAY_USER_REPLUG);
fu_device_convert_instance_ids (device1);
fu_device_set_id (device2, "device2");
fu_device_add_instance_id (device2, "baz");
fu_device_add_instance_id (device2, "bar"); /* matches */
fu_device_set_plugin (device2, "self-test");
fu_device_set_remove_delay (device2, FU_DEVICE_REMOVE_DELAY_USER_REPLUG);
fu_device_convert_instance_ids (device2);
/* not yet added */
ret = fu_device_list_wait_for_replug (device_list, device1, &error);
g_assert_no_error (error);
g_assert (ret);
/* add device */
fu_device_list_add (device_list, device1);
/* not waiting */
ret = fu_device_list_wait_for_replug (device_list, device1, &error);
g_assert_no_error (error);
g_assert (ret);
/* waiting */
helper.device_old = device1;
helper.device_new = device2;
helper.device_list = device_list;
g_timeout_add (100, fu_device_list_remove_cb, &helper);
g_timeout_add (200, fu_device_list_add_cb, &helper);
fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG);
ret = fu_device_list_wait_for_replug (device_list, device1, &error);
g_assert_no_error (error);
g_assert (ret);
}
static void
fu_device_list_compatible_func (void)
{
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(FuDevice) device_old = NULL;
g_autoptr(FuDeviceList) device_list = fu_device_list_new ();
g_autoptr(GPtrArray) devices_all = NULL;
g_autoptr(GPtrArray) devices_active = NULL;
FuDevice *device;
guint added_cnt = 0;
guint changed_cnt = 0;
guint removed_cnt = 0;
g_signal_connect (device_list, "added",
G_CALLBACK (_device_list_count_cb),
&added_cnt);
g_signal_connect (device_list, "removed",
G_CALLBACK (_device_list_count_cb),
&removed_cnt);
g_signal_connect (device_list, "changed",
G_CALLBACK (_device_list_count_cb),
&changed_cnt);
/* add one device in runtime mode */
fu_device_set_id (device1, "device1");
fu_device_set_plugin (device1, "plugin-for-runtime");
fu_device_set_vendor_id (device1, "USB:0x20A0");
fu_device_set_version (device1, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_add_instance_id (device1, "foobar");
fu_device_add_instance_id (device1, "bootloader");
fu_device_set_remove_delay (device1, 100);
fu_device_convert_instance_ids (device1);
fu_device_list_add (device_list, device1);
g_assert_cmpint (added_cnt, ==, 1);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 0);
/* add another device in bootloader mode */
fu_device_set_id (device2, "device2");
fu_device_set_plugin (device2, "plugin-for-bootloader");
fu_device_add_instance_id (device2, "bootloader");
fu_device_convert_instance_ids (device2);
/* verify only a changed event was generated */
added_cnt = removed_cnt = changed_cnt = 0;
fu_device_list_remove (device_list, device1);
fu_device_list_add (device_list, device2);
g_assert_cmpint (added_cnt, ==, 0);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 1);
/* device2 should inherit the vendor ID and version from device1 */
g_assert_cmpstr (fu_device_get_vendor_id (device2), ==, "USB:0x20A0");
g_assert_cmpstr (fu_device_get_version (device2), ==, "1.2.3");
/* one device is active */
devices_active = fu_device_list_get_active (device_list);
g_assert_cmpint (devices_active->len, ==, 1);
device = g_ptr_array_index (devices_active, 0);
g_assert_cmpstr (fu_device_get_id (device), ==,
"1a8d0d9a96ad3e67ba76cf3033623625dc6d6882");
/* the list knows about both devices, list in order of active->old */
devices_all = fu_device_list_get_all (device_list);
g_assert_cmpint (devices_all->len, ==, 2);
device = g_ptr_array_index (devices_all, 0);
g_assert_cmpstr (fu_device_get_id (device), ==,
"1a8d0d9a96ad3e67ba76cf3033623625dc6d6882");
device = g_ptr_array_index (devices_all, 1);
g_assert_cmpstr (fu_device_get_id (device), ==,
"99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a");
/* verify we can get the old device from the new device */
device_old = fu_device_list_get_old (device_list, device2);
g_assert (device_old == device1);
}
static void
fu_device_list_remove_chain_func (void)
{
g_autoptr(FuDeviceList) device_list = fu_device_list_new ();
g_autoptr(FuDevice) device_child = fu_device_new ();
g_autoptr(FuDevice) device_parent = fu_device_new ();
guint added_cnt = 0;
guint changed_cnt = 0;
guint removed_cnt = 0;
g_signal_connect (device_list, "added",
G_CALLBACK (_device_list_count_cb),
&added_cnt);
g_signal_connect (device_list, "removed",
G_CALLBACK (_device_list_count_cb),
&removed_cnt);
g_signal_connect (device_list, "changed",
G_CALLBACK (_device_list_count_cb),
&changed_cnt);
/* add child */
fu_device_set_id (device_child, "child");
fu_device_add_instance_id (device_child, "child-GUID-1");
fu_device_convert_instance_ids (device_child);
fu_device_list_add (device_list, device_child);
g_assert_cmpint (added_cnt, ==, 1);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 0);
/* add parent */
fu_device_set_id (device_parent, "parent");
fu_device_add_instance_id (device_parent, "parent-GUID-1");
fu_device_convert_instance_ids (device_parent);
fu_device_add_child (device_parent, device_child);
fu_device_list_add (device_list, device_parent);
g_assert_cmpint (added_cnt, ==, 2);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 0);
/* make sure that removing the parent causes both to go; but the child to go first */
fu_device_list_remove (device_list, device_parent);
g_assert_cmpint (added_cnt, ==, 2);
g_assert_cmpint (removed_cnt, ==, 2);
g_assert_cmpint (changed_cnt, ==, 0);
}
static void
fu_device_list_func (void)
{
g_autoptr(FuDeviceList) device_list = fu_device_list_new ();
g_autoptr(FuDevice) device1 = fu_device_new ();
g_autoptr(FuDevice) device2 = fu_device_new ();
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GPtrArray) devices2 = NULL;
g_autoptr(GError) error = NULL;
FuDevice *device;
guint added_cnt = 0;
guint changed_cnt = 0;
guint removed_cnt = 0;
g_signal_connect (device_list, "added",
G_CALLBACK (_device_list_count_cb),
&added_cnt);
g_signal_connect (device_list, "removed",
G_CALLBACK (_device_list_count_cb),
&removed_cnt);
g_signal_connect (device_list, "changed",
G_CALLBACK (_device_list_count_cb),
&changed_cnt);
/* add both */
fu_device_set_id (device1, "device1");
fu_device_add_instance_id (device1, "foobar");
fu_device_convert_instance_ids (device1);
fu_device_list_add (device_list, device1);
fu_device_set_id (device2, "device2");
fu_device_add_instance_id (device2, "baz");
fu_device_convert_instance_ids (device2);
fu_device_list_add (device_list, device2);
g_assert_cmpint (added_cnt, ==, 2);
g_assert_cmpint (removed_cnt, ==, 0);
g_assert_cmpint (changed_cnt, ==, 0);
/* get all */
devices = fu_device_list_get_all (device_list);
g_assert_cmpint (devices->len, ==, 2);
device = g_ptr_array_index (devices, 0);
g_assert_cmpstr (fu_device_get_id (device), ==,
"99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a");
/* find by ID */
device = fu_device_list_get_by_id (device_list,
"99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a",
&error);
g_assert_no_error (error);
g_assert (device != NULL);
g_assert_cmpstr (fu_device_get_id (device), ==,
"99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a");
g_clear_object (&device);
/* find by GUID */
device = fu_device_list_get_by_guid (device_list,
"579a3b1c-d1db-5bdc-b6b9-e2c1b28d5b8a",
&error);
g_assert_no_error (error);
g_assert (device != NULL);
g_assert_cmpstr (fu_device_get_id (device), ==,
"1a8d0d9a96ad3e67ba76cf3033623625dc6d6882");
g_clear_object (&device);
/* find by missing GUID */
device = fu_device_list_get_by_guid (device_list, "notfound", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (device == NULL);
/* remove device */
added_cnt = removed_cnt = changed_cnt = 0;
fu_device_list_remove (device_list, device1);
g_assert_cmpint (added_cnt, ==, 0);
g_assert_cmpint (removed_cnt, ==, 1);
g_assert_cmpint (changed_cnt, ==, 0);
devices2 = fu_device_list_get_all (device_list);
g_assert_cmpint (devices2->len, ==, 1);
device = g_ptr_array_index (devices2, 0);
g_assert_cmpstr (fu_device_get_id (device), ==,
"1a8d0d9a96ad3e67ba76cf3033623625dc6d6882");
}
static void
fu_device_version_format_func (void)
{
g_autoptr(FuDevice) device = fu_device_new ();
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ENSURE_SEMVER);
fu_device_set_version (device, "Ver1.2.3 RELEASE", FWUPD_VERSION_FORMAT_TRIPLET);
g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3");
}
static void
fu_device_open_refcount_func (void)
{
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(GError) error = NULL;
fu_device_set_id (device, "test_device");
ret = fu_device_open (device, &error);
g_assert_no_error (error);
g_assert_true (ret);
ret = fu_device_open (device, &error);
g_assert_no_error (error);
g_assert_true (ret);
ret = fu_device_close (device, &error);
g_assert_no_error (error);
g_assert_true (ret);
ret = fu_device_close (device, &error);
g_assert_no_error (error);
g_assert_true (ret);
ret = fu_device_close (device, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL);
g_assert_false (ret);
}
static void
fu_device_metadata_func (void)
{
g_autoptr(FuDevice) device = fu_device_new ();
/* string */
fu_device_set_metadata (device, "foo", "bar");
g_assert_cmpstr (fu_device_get_metadata (device, "foo"), ==, "bar");
fu_device_set_metadata (device, "foo", "baz");
g_assert_cmpstr (fu_device_get_metadata (device, "foo"), ==, "baz");
g_assert_null (fu_device_get_metadata (device, "unknown"));
/* boolean */
fu_device_set_metadata_boolean (device, "baz", TRUE);
g_assert_cmpstr (fu_device_get_metadata (device, "baz"), ==, "true");
g_assert_true (fu_device_get_metadata_boolean (device, "baz"));
g_assert_false (fu_device_get_metadata_boolean (device, "unknown"));
/* integer */
fu_device_set_metadata_integer (device, "dum", 12345);
g_assert_cmpstr (fu_device_get_metadata (device, "dum"), ==, "12345");
g_assert_cmpint (fu_device_get_metadata_integer (device, "dum"), ==, 12345);
g_assert_cmpint (fu_device_get_metadata_integer (device, "unknown"), ==, G_MAXUINT);
/* broken integer */
fu_device_set_metadata (device, "dum", "123junk");
g_assert_cmpint (fu_device_get_metadata_integer (device, "dum"), ==, G_MAXUINT);
fu_device_set_metadata (device, "huge", "4294967296"); /* not 32 bit */
g_assert_cmpint (fu_device_get_metadata_integer (device, "huge"), ==, G_MAXUINT);
}
static void
fu_smbios_func (void)
{
const gchar *str;
gboolean ret;
g_autofree gchar *dump = NULL;
g_autoptr(FuSmbios) smbios = NULL;
g_autoptr(GError) error = NULL;
smbios = fu_smbios_new ();
ret = fu_smbios_setup (smbios, &error);
g_assert_no_error (error);
g_assert (ret);
dump = fu_smbios_to_string (smbios);
if (g_getenv ("VERBOSE") != NULL)
g_debug ("%s", dump);
/* test for missing table */
str = fu_smbios_get_string (smbios, 0xff, 0, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert_null (str);
g_clear_error (&error);
/* check for invalid offset */
str = fu_smbios_get_string (smbios, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0xff, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert_null (str);
g_clear_error (&error);
/* get vendor */
str = fu_smbios_get_string (smbios, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x04, &error);
g_assert_no_error (error);
g_assert_cmpstr (str, ==, "LENOVO");
}
static void
fu_smbios3_func (void)
{
const gchar *str;
gboolean ret;
g_autofree gchar *path = NULL;
g_autoptr(FuSmbios) smbios = NULL;
g_autoptr(GError) error = NULL;
path = fu_test_get_filename (TESTDATADIR, "dmi/tables64");
g_assert_nonnull (path);
smbios = fu_smbios_new ();
ret = fu_smbios_setup_from_path (smbios, path, &error);
g_assert_no_error (error);
g_assert (ret);
if (g_getenv ("VERBOSE") != NULL) {
g_autofree gchar *dump = fu_smbios_to_string (smbios);
g_debug ("%s", dump);
}
/* get vendor */
str = fu_smbios_get_string (smbios, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x04, &error);
g_assert_no_error (error);
g_assert_cmpstr (str, ==, "Dell Inc.");
}
static void
fu_hwids_func (void)
{
g_autoptr(FuHwids) hwids = NULL;
g_autoptr(FuSmbios) smbios = NULL;
g_autoptr(GError) error = NULL;
gboolean ret;
struct {
const gchar *key;
const gchar *value;
} guids[] = {
{ "Manufacturer", "6de5d951-d755-576b-bd09-c5cf66b27234" },
{ "HardwareID-14", "6de5d951-d755-576b-bd09-c5cf66b27234" },
{ "HardwareID-13", "f8e1de5f-b68c-5f52-9d1a-f1ba52f1f773" },
{ "HardwareID-12", "e093d715-70f7-51f4-b6c8-b4a7e31def85" },
{ "HardwareID-11", "db73af4c-4612-50f7-b8a7-787cf4871847" },
{ "HardwareID-10", "f4275c1f-6130-5191-845c-3426247eb6a1" },
{ "HardwareID-9", "0cf8618d-9eff-537c-9f35-46861406eb9c" },
{ "HardwareID-8", "059eb22d-6dc7-59af-abd3-94bbe017f67c" },
{ "HardwareID-7", "da1da9b6-62f5-5f22-8aaa-14db7eeda2a4" },
{ "HardwareID-6", "178cd22d-ad9f-562d-ae0a-34009822cdbe" },
{ "HardwareID-5", "8dc9b7c5-f5d5-5850-9ab3-bd6f0549d814" },
{ "HardwareID-4", "660ccba8-1b78-5a33-80e6-9fb8354ee873" },
{ "HardwareID-3", "3faec92a-3ae3-5744-be88-495e90a7d541" },
{ "HardwareID-2", "f5ff077f-3eeb-5bae-be1c-e98ffe8ce5f8" },
{ "HardwareID-1", "b7cceb67-774c-537e-bf8b-22c6107e9a74" },
{ "HardwareID-0", "147efce9-f201-5fc8-ab0c-c859751c3440" },
{ NULL, NULL }
};
smbios = fu_smbios_new ();
ret = fu_smbios_setup (smbios, &error);
g_assert_no_error (error);
g_assert (ret);
hwids = fu_hwids_new ();
ret = fu_hwids_setup (hwids, smbios, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_MANUFACTURER), ==,
"LENOVO");
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_ENCLOSURE_KIND), ==,
"a");
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_FAMILY), ==,
"ThinkPad T440s");
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_PRODUCT_NAME), ==,
"20ARS19C0C");
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_VENDOR), ==,
"LENOVO");
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_VERSION), ==,
"GJET75WW (2.25 )");
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE), ==, "02");
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_MINOR_RELEASE), ==, "19");
g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_PRODUCT_SKU), ==,
"LENOVO_MT_20AR_BU_Think_FM_ThinkPad T440s");
for (guint i = 0; guids[i].key != NULL; i++) {
g_autofree gchar *guid = fu_hwids_get_guid (hwids, guids[i].key, &error);
g_assert_no_error (error);
g_assert_cmpstr (guid, ==, guids[i].value);
}
for (guint i = 0; guids[i].key != NULL; i++)
g_assert (fu_hwids_has_guid (hwids, guids[i].value));
}
static void
_plugin_status_changed_cb (FuDevice *device, GParamSpec *pspec, gpointer user_data)
{
guint *cnt = (guint *) user_data;
g_debug ("device %s now %s",
fu_device_get_id (device),
fwupd_status_to_string (fu_device_get_status (device)));
(*cnt)++;
fu_test_loop_quit ();
}
static void
_plugin_device_added_cb (FuPlugin *plugin, FuDevice *device, gpointer user_data)
{
FuDevice **dev = (FuDevice **) user_data;
*dev = g_object_ref (device);
fu_test_loop_quit ();
}
static void
fu_plugin_delay_func (void)
{
FuDevice *device_tmp;
g_autoptr(FuPlugin) plugin = NULL;
g_autoptr(FuDevice) device = NULL;
plugin = fu_plugin_new ();
g_signal_connect (plugin, "device-added",
G_CALLBACK (_plugin_device_added_cb),
&device_tmp);
g_signal_connect (plugin, "device-removed",
G_CALLBACK (_plugin_device_added_cb),
&device_tmp);
/* add device straight away */
device = fu_device_new ();
fu_device_set_id (device, "testdev");
fu_plugin_device_add (plugin, device);
g_assert (device_tmp != NULL);
g_assert_cmpstr (fu_device_get_id (device_tmp), ==, "b7eccd0059d6d7dc2ef76c35d6de0048cc8c029d");
g_clear_object (&device_tmp);
/* remove device */
fu_plugin_device_remove (plugin, device);
g_assert (device_tmp != NULL);
g_assert_cmpstr (fu_device_get_id (device_tmp), ==, "b7eccd0059d6d7dc2ef76c35d6de0048cc8c029d");
g_clear_object (&device_tmp);
}
static void
_plugin_device_register_cb (FuPlugin *plugin, FuDevice *device, gpointer user_data)
{
/* fake being a daemon */
fu_plugin_runner_device_register (plugin, device);
}
static void
fu_plugin_quirks_func (void)
{
const gchar *tmp;
gboolean ret;
g_autoptr(FuQuirks) quirks = fu_quirks_new ();
g_autoptr(FuPlugin) plugin = fu_plugin_new ();
g_autoptr(GError) error = NULL;
ret = fu_quirks_load (quirks, &error);
g_assert_no_error (error);
g_assert (ret);
fu_plugin_set_quirks (plugin, quirks);
/* exact */
tmp = fu_plugin_lookup_quirk_by_id (plugin, "USB\\VID_0A5C&PID_6412", "Flags");
g_assert_cmpstr (tmp, ==, "MERGE_ME,ignore-runtime");
tmp = fu_plugin_lookup_quirk_by_id (plugin, "ACME Inc.=True", "Test");
g_assert_cmpstr (tmp, ==, "awesome");
tmp = fu_plugin_lookup_quirk_by_id (plugin, "CORP*", "Test");
g_assert_cmpstr (tmp, ==, "town");
tmp = fu_plugin_lookup_quirk_by_id (plugin, "USB\\VID_FFFF&PID_FFFF", "Flags");
g_assert_cmpstr (tmp, ==, "");
tmp = fu_plugin_lookup_quirk_by_id (plugin, "baz", "Unfound");
g_assert_cmpstr (tmp, ==, NULL);
tmp = fu_plugin_lookup_quirk_by_id (plugin, "unfound", "tests");
g_assert_cmpstr (tmp, ==, NULL);
tmp = fu_plugin_lookup_quirk_by_id (plugin, "unfound", "unfound");
g_assert_cmpstr (tmp, ==, NULL);
tmp = fu_plugin_lookup_quirk_by_id (plugin, "bb9ec3e2-77b3-53bc-a1f1-b05916715627", "Flags");
g_assert_cmpstr (tmp, ==, "clever");
}
static void
fu_plugin_quirks_performance_func (void)
{
g_autoptr(FuQuirks) quirks = fu_quirks_new ();
g_autoptr(GTimer) timer = g_timer_new ();
const gchar *keys[] = {
"Name", "Icon", "Children", "Plugin", "Flags",
"FirmwareSizeMin", "FirmwareSizeMax", NULL };
/* insert */
for (guint j = 0; j < 1000; j++) {
g_autofree gchar *group = NULL;
group = g_strdup_printf ("DeviceInstanceId=USB\\VID_0BDA&PID_%04X", j);
for (guint i = 0; keys[i] != NULL; i++)
fu_quirks_add_value (quirks, group, keys[i], "Value");
}
g_print ("insert=%.3fms ", g_timer_elapsed (timer, NULL) * 1000.f);
/* lookup */
g_timer_reset (timer);
for (guint j = 0; j < 1000; j++) {
g_autofree gchar *group = NULL;
group = g_strdup_printf ("DeviceInstanceId=USB\\VID_0BDA&PID_%04X", j);
for (guint i = 0; keys[i] != NULL; i++) {
const gchar *tmp = fu_quirks_lookup_by_id (quirks, group, keys[i]);
g_assert_cmpstr (tmp, ==, "Value");
}
}
g_print ("lookup=%.3fms ", g_timer_elapsed (timer, NULL) * 1000.f);
}
static void
fu_plugin_quirks_device_func (void)
{
FuDevice *device_tmp;
GPtrArray *children;
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuQuirks) quirks = fu_quirks_new ();
g_autoptr(GError) error = NULL;
ret = fu_quirks_load (quirks, &error);
g_assert_no_error (error);
g_assert (ret);
/* use quirk file to set device attributes */
fu_device_set_physical_id (device, "usb:00:05");
fu_device_set_quirks (device, quirks);
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_instance_id (device, "USB\\VID_0BDA&PID_1100");
fu_device_convert_instance_ids (device);
g_assert_cmpstr (fu_device_get_name (device), ==, "Hub");
/* ensure children are created */
children = fu_device_get_children (device);
g_assert_cmpint (children->len, ==, 1);
device_tmp = g_ptr_array_index (children, 0);
g_assert_cmpstr (fu_device_get_name (device_tmp), ==, "HDMI");
g_assert (fu_device_has_flag (device_tmp, FWUPD_DEVICE_FLAG_UPDATABLE));
}
static void
fu_plugin_hash_func (void)
{
GError *error = NULL;
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuPlugin) plugin = fu_plugin_new ();
gboolean ret = FALSE;
ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
/* make sure not tainted */
ret = fu_engine_get_tainted (engine);
g_assert_false (ret);
/* create a tainted plugin */
g_setenv ("FWUPD_PLUGIN_TEST", "build-hash", TRUE);
ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error);
g_assert_no_error (error);
/* make sure it tainted now */
g_test_expect_message ("FuEngine", G_LOG_LEVEL_WARNING, "* has incorrect built version*");
fu_engine_add_plugin (engine, plugin);
ret = fu_engine_get_tainted (engine);
g_assert_true (ret);
}
static void
fu_plugin_module_func (void)
{
GError *error = NULL;
FuDevice *device_tmp;
FwupdRelease *release;
gboolean ret;
guint cnt = 0;
g_autofree gchar *localstatedir = NULL;
g_autofree gchar *mapped_file_fn = NULL;
g_autofree gchar *pending_cap = NULL;
g_autofree gchar *history_db = NULL;
g_autoptr(FuDevice) device = NULL;
g_autoptr(FuDevice) device2 = NULL;
g_autoptr(FuDevice) device3 = NULL;
g_autoptr(FuHistory) history = NULL;
g_autoptr(FuPlugin) plugin = NULL;
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GMappedFile) mapped_file = NULL;
/* create a fake device */
plugin = fu_plugin_new ();
g_setenv ("FWUPD_PLUGIN_TEST", "registration", TRUE);
ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error);
g_assert_no_error (error);
g_assert (ret);
ret = fu_plugin_runner_startup (plugin, &error);
g_assert_no_error (error);
g_assert (ret);
g_signal_connect (plugin, "device-added",
G_CALLBACK (_plugin_device_added_cb),
&device);
g_signal_connect (plugin, "device-register",
G_CALLBACK (_plugin_device_register_cb),
&device);
ret = fu_plugin_runner_coldplug (plugin, &error);
g_assert_no_error (error);
g_assert (ret);
/* check we did the right thing */
g_assert (device != NULL);
g_assert_cmpstr (fu_device_get_id (device), ==, "08d460be0f1f9f128413f816022a6439e0078018");
g_assert_cmpstr (fu_device_get_version_lowest (device), ==, "1.2.0");
g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.2");
g_assert_cmpstr (fu_device_get_version_bootloader (device), ==, "0.1.2");
g_assert_cmpstr (fu_device_get_guid_default (device), ==,
"b585990a-003e-5270-89d5-3705a17f9a43");
g_assert_cmpstr (fu_device_get_name (device), ==,
"Integrated Webcam™");
/* schedule an offline update */
g_signal_connect (device, "notify::status",
G_CALLBACK (_plugin_status_changed_cb),
&cnt);
mapped_file_fn = fu_test_get_filename (TESTDATADIR, "colorhug/firmware.bin");
mapped_file = g_mapped_file_new (mapped_file_fn, FALSE, &error);
g_assert_no_error (error);
g_assert (mapped_file != NULL);
blob_cab = g_mapped_file_get_bytes (mapped_file);
release = fu_device_get_release_default (device);
fwupd_release_set_version (release, "1.2.3");
ret = fu_plugin_runner_schedule_update (plugin, device, release, blob_cab,
FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (cnt, ==, 1);
/* set on the current device */
g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT));
/* lets check the history */
history = fu_history_new ();
device2 = fu_history_get_device_by_id (history, fu_device_get_id (device), &error);
g_assert_no_error (error);
g_assert (device2 != NULL);
g_assert_cmpint (fu_device_get_update_state (device2), ==, FWUPD_UPDATE_STATE_PENDING);
g_assert_cmpstr (fu_device_get_update_error (device2), ==, NULL);
g_assert_true (fu_device_has_flag (device2, FWUPD_DEVICE_FLAG_NEEDS_REBOOT));
release = fu_device_get_release_default (device2);
g_assert (release != NULL);
g_assert_cmpstr (fwupd_release_get_filename (release), !=, NULL);
g_assert_cmpstr (fwupd_release_get_version (release), ==, "1.2.3");
/* save this; we'll need to delete it later */
pending_cap = g_strdup (fwupd_release_get_filename (release));
/* lets do this online */
ret = fu_plugin_runner_update (plugin, device, blob_cab,
FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (cnt, ==, 4);
/* check the new version */
g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3");
g_assert_cmpstr (fu_device_get_version_bootloader (device), ==, "0.1.2");
/* lets check the history */
device3 = fu_history_get_device_by_id (history, fu_device_get_id (device), &error);
g_assert_no_error (error);
g_assert (device3 != NULL);
g_assert_cmpint (fu_device_get_update_state (device3), ==, FWUPD_UPDATE_STATE_SUCCESS);
g_assert_cmpstr (fu_device_get_update_error (device3), ==, NULL);
/* get the status */
device_tmp = fu_device_new ();
fu_device_set_id (device_tmp, "FakeDevice");
ret = fu_plugin_runner_get_results (plugin, device_tmp, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (fu_device_get_update_state (device_tmp), ==, FWUPD_UPDATE_STATE_SUCCESS);
g_assert_cmpstr (fu_device_get_update_error (device_tmp), ==, NULL);
/* clear */
ret = fu_plugin_runner_clear_results (plugin, device_tmp, &error);
g_assert_no_error (error);
g_assert (ret);
g_object_unref (device_tmp);
g_clear_error (&error);
/* delete files */
localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
history_db = g_build_filename (localstatedir, "pending.db", NULL);
g_unlink (history_db);
g_unlink (pending_cap);
}
static void
fu_plugin_list_func (void)
{
GPtrArray *plugins;
FuPlugin *plugin;
g_autoptr(FuPluginList) plugin_list = fu_plugin_list_new ();
g_autoptr(FuPlugin) plugin1 = fu_plugin_new ();
g_autoptr(FuPlugin) plugin2 = fu_plugin_new ();
g_autoptr(GError) error = NULL;
fu_plugin_set_name (plugin1, "plugin1");
fu_plugin_set_name (plugin2, "plugin2");
/* get all the plugins */
fu_plugin_list_add (plugin_list, plugin1);
fu_plugin_list_add (plugin_list, plugin2);
plugins = fu_plugin_list_get_all (plugin_list);
g_assert_cmpint (plugins->len, ==, 2);
/* get a single plugin */
plugin = fu_plugin_list_find_by_name (plugin_list, "plugin1", &error);
g_assert_no_error (error);
g_assert (plugin != NULL);
g_assert_cmpstr (fu_plugin_get_name (plugin), ==, "plugin1");
/* does not exist */
plugin = fu_plugin_list_find_by_name (plugin_list, "nope", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (plugin == NULL);
}
static void
fu_plugin_list_depsolve_func (void)
{
GPtrArray *plugins;
FuPlugin *plugin;
gboolean ret;
g_autoptr(FuPluginList) plugin_list = fu_plugin_list_new ();
g_autoptr(FuPlugin) plugin1 = fu_plugin_new ();
g_autoptr(FuPlugin) plugin2 = fu_plugin_new ();
g_autoptr(GError) error = NULL;
fu_plugin_set_name (plugin1, "plugin1");
fu_plugin_set_name (plugin2, "plugin2");
/* add rule then depsolve */
fu_plugin_list_add (plugin_list, plugin1);
fu_plugin_list_add (plugin_list, plugin2);
fu_plugin_add_rule (plugin1, FU_PLUGIN_RULE_RUN_AFTER, "plugin2");
ret = fu_plugin_list_depsolve (plugin_list, &error);
g_assert_no_error (error);
g_assert (ret);
plugins = fu_plugin_list_get_all (plugin_list);
g_assert_cmpint (plugins->len, ==, 2);
plugin = g_ptr_array_index (plugins, 0);
g_assert_cmpstr (fu_plugin_get_name (plugin), ==, "plugin2");
g_assert_cmpint (fu_plugin_get_order (plugin), ==, 0);
g_assert (fu_plugin_get_enabled (plugin));
/* add another rule, then re-depsolve */
fu_plugin_add_rule (plugin1, FU_PLUGIN_RULE_CONFLICTS, "plugin2");
ret = fu_plugin_list_depsolve (plugin_list, &error);
g_assert_no_error (error);
g_assert (ret);
plugin = fu_plugin_list_find_by_name (plugin_list, "plugin1", &error);
g_assert_no_error (error);
g_assert (plugin != NULL);
g_assert (fu_plugin_get_enabled (plugin));
plugin = fu_plugin_list_find_by_name (plugin_list, "plugin2", &error);
g_assert_no_error (error);
g_assert (plugin != NULL);
g_assert (!fu_plugin_get_enabled (plugin));
}
static void
fu_history_migrate_func (void)
{
gboolean ret;
g_autoptr(GError) error = NULL;
g_autoptr(GFile) file_dst = NULL;
g_autoptr(GFile) file_src = NULL;
g_autoptr(FuDevice) device = NULL;
g_autoptr(FuHistory) history = NULL;
g_autofree gchar *filename = NULL;
/* load old version */
filename = fu_test_get_filename (TESTDATADIR, "history_v1.db");
file_src = g_file_new_for_path (filename);
file_dst = g_file_new_for_path ("/tmp/fwupd-self-test/var/lib/fwupd/pending.db");
ret = g_file_copy (file_src, file_dst, G_FILE_COPY_OVERWRITE, NULL,
NULL, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
/* create, migrating as required */
history = fu_history_new ();
g_assert (history != NULL);
/* get device */
device = fu_history_get_device_by_id (history, "2ba16d10df45823dd4494ff10a0bfccfef512c9d", &error);
g_assert_no_error (error);
g_assert (device != NULL);
g_assert_cmpstr (fu_device_get_id (device), ==, "2ba16d10df45823dd4494ff10a0bfccfef512c9d");
}
static void
fu_history_func (void)
{
GError *error = NULL;
GPtrArray *checksums;
gboolean ret;
FuDevice *device;
FwupdRelease *release;
g_autoptr(FuDevice) device_found = NULL;
g_autoptr(FuHistory) history = NULL;
g_autoptr(GPtrArray) approved_firmware = NULL;
g_autofree gchar *dirname = NULL;
g_autofree gchar *filename = NULL;
/* create */
history = fu_history_new ();
g_assert (history != NULL);
/* delete the database */
dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
if (!g_file_test (dirname, G_FILE_TEST_IS_DIR))
return;
filename = g_build_filename (dirname, "pending.db", NULL);
g_unlink (filename);
/* add a device */
device = fu_device_new ();
fu_device_set_id (device, "self-test");
fu_device_set_name (device, "ColorHug"),
fu_device_set_version (device, "3.0.1", FWUPD_VERSION_FORMAT_TRIPLET),
fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED);
fu_device_set_update_error (device, "word");
fu_device_add_guid (device, "827edddd-9bb6-5632-889f-2c01255503da");
fu_device_set_flags (device, FWUPD_DEVICE_FLAG_INTERNAL);
fu_device_set_created (device, 123);
fu_device_set_modified (device, 456);
release = fwupd_release_new ();
fwupd_release_set_filename (release, "/var/lib/dave.cap"),
fwupd_release_add_checksum (release, "abcdef");
fwupd_release_set_version (release, "3.0.2");
fwupd_release_add_metadata_item (release, "FwupdVersion", VERSION);
ret = fu_history_add_device (history, device, release, &error);
g_assert_no_error (error);
g_assert (ret);
g_object_unref (release);
/* ensure database was created */
g_assert (g_file_test (filename, G_FILE_TEST_EXISTS));
g_object_unref (device);
/* get device */
device = fu_history_get_device_by_id (history, "2ba16d10df45823dd4494ff10a0bfccfef512c9d", &error);
g_assert_no_error (error);
g_assert (device != NULL);
g_assert_cmpstr (fu_device_get_id (device), ==, "2ba16d10df45823dd4494ff10a0bfccfef512c9d");
g_assert_cmpstr (fu_device_get_name (device), ==, "ColorHug");
g_assert_cmpstr (fu_device_get_version (device), ==, "3.0.1");
g_assert_cmpint (fu_device_get_update_state (device), ==, FWUPD_UPDATE_STATE_FAILED);
g_assert_cmpstr (fu_device_get_update_error (device), ==, "word");
g_assert_cmpstr (fu_device_get_guid_default (device), ==, "827edddd-9bb6-5632-889f-2c01255503da");
g_assert_cmpint (fu_device_get_flags (device), ==, FWUPD_DEVICE_FLAG_INTERNAL);
g_assert_cmpint (fu_device_get_created (device), ==, 123);
g_assert_cmpint (fu_device_get_modified (device), ==, 456);
release = fu_device_get_release_default (device);
g_assert (release != NULL);
g_assert_cmpstr (fwupd_release_get_version (release), ==, "3.0.2");
g_assert_cmpstr (fwupd_release_get_filename (release), ==, "/var/lib/dave.cap");
g_assert_cmpstr (fwupd_release_get_metadata_item (release, "FwupdVersion"), ==, VERSION);
checksums = fwupd_release_get_checksums (release);
g_assert (checksums != NULL);
g_assert_cmpint (checksums->len, ==, 1);
g_assert_cmpstr (fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1), ==, "abcdef");
ret = fu_history_add_device (history, device, release, &error);
g_assert_no_error (error);
g_assert (ret);
/* get device that does not exist */
device_found = fu_history_get_device_by_id (history, "XXXXXXXXXXXXX", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (device_found == NULL);
g_clear_error (&error);
/* get device that does exist */
device_found = fu_history_get_device_by_id (history, "2ba16d10df45823dd4494ff10a0bfccfef512c9d", &error);
g_assert_no_error (error);
g_assert (device_found != NULL);
g_object_unref (device_found);
/* remove device */
ret = fu_history_remove_device (history, device, release, &error);
g_assert_no_error (error);
g_assert (ret);
g_object_unref (device);
/* get device that does not exist */
device_found = fu_history_get_device_by_id (history, "2ba16d10df45823dd4494ff10a0bfccfef512c9d", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (device_found == NULL);
g_clear_error (&error);
/* approved firmware */
ret = fu_history_clear_approved_firmware (history, &error);
g_assert_no_error (error);
g_assert (ret);
ret = fu_history_add_approved_firmware (history, "foo", &error);
g_assert_no_error (error);
g_assert (ret);
ret = fu_history_add_approved_firmware (history, "bar", &error);
g_assert_no_error (error);
g_assert (ret);
approved_firmware = fu_history_get_approved_firmware (history, &error);
g_assert_no_error (error);
g_assert_nonnull (approved_firmware);
g_assert_cmpint (approved_firmware->len, ==, 2);
g_assert_cmpstr (g_ptr_array_index (approved_firmware, 0), ==, "foo");
g_assert_cmpstr (g_ptr_array_index (approved_firmware, 1), ==, "bar");
}
static void
fu_keyring_gpg_func (void)
{
#ifdef ENABLE_GPG
gboolean ret;
g_autofree gchar *fw_fail = NULL;
g_autofree gchar *fw_pass = NULL;
g_autofree gchar *pki_dir = NULL;
g_autoptr(FuKeyring) keyring = NULL;
g_autoptr(FuKeyringResult) result_fail = NULL;
g_autoptr(FuKeyringResult) result_pass = NULL;
g_autoptr(GBytes) blob_fail = NULL;
g_autoptr(GBytes) blob_pass = NULL;
g_autoptr(GBytes) blob_sig = NULL;
g_autoptr(GError) error = NULL;
const gchar *sig_gpgme =
"-----BEGIN PGP SIGNATURE-----\n"
"Version: GnuPG v1\n\n"
"iQEcBAABCAAGBQJVt0B4AAoJEEim2A5FOLrCFb8IAK+QTLY34Wu8xZ8nl6p3JdMu"
"HOaifXAmX7291UrsFRwdabU2m65pqxQLwcoFrqGv738KuaKtu4oIwo9LIrmmTbEh"
"IID8uszxBt0bMdcIHrvwd+ADx+MqL4hR3guXEE3YOBTLvv2RF1UBcJPInNf/7Ui1"
"3lW1c3trL8RAJyx1B5RdKqAMlyfwiuvKM5oT4SN4uRSbQf+9mt78ZSWfJVZZH/RR"
"H9q7PzR5GdmbsRPM0DgC27Trvqjo3MzoVtoLjIyEb/aWqyulUbnJUNKPYTnZgkzM"
"v2yVofWKIM3e3wX5+MOtf6EV58mWa2cHJQ4MCYmpKxbIvAIZagZ4c9A8BA6tQWg="
"=fkit\n"
"-----END PGP SIGNATURE-----\n";
/* add keys to keyring */
keyring = fu_keyring_gpg_new ();
ret = fu_keyring_setup (keyring, &error);
g_assert_no_error (error);
g_assert_true (ret);
pki_dir = fu_test_get_filename (TESTDATADIR, "pki");
g_assert_nonnull (pki_dir);
ret = fu_keyring_add_public_keys (keyring, pki_dir, &error);
g_assert_no_error (error);
g_assert_true (ret);
/* verify with GnuPG */
fw_pass = fu_test_get_filename (TESTDATADIR, "colorhug/firmware.bin");
g_assert_nonnull (fw_pass);
blob_pass = fu_common_get_contents_bytes (fw_pass, &error);
g_assert_no_error (error);
g_assert_nonnull (blob_pass);
blob_sig = g_bytes_new_static (sig_gpgme, strlen (sig_gpgme));
result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig,
FU_KEYRING_VERIFY_FLAG_NONE,
&error);
g_assert_no_error (error);
g_assert_nonnull (result_pass);
g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), == , 1438072952);
g_assert_cmpstr (fu_keyring_result_get_authority (result_pass), == ,
"3FC6B804410ED0840D8F2F9748A6D80E4538BAC2");
/* verify will fail with GnuPG */
fw_fail = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab");
g_assert_nonnull (fw_fail);
blob_fail = fu_common_get_contents_bytes (fw_fail, &error);
g_assert_no_error (error);
g_assert_nonnull (blob_fail);
result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig,
FU_KEYRING_VERIFY_FLAG_NONE, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID);
g_assert_null (result_fail);
g_clear_error (&error);
#else
g_test_skip ("no GnuPG support enabled");
#endif
}
static void
fu_keyring_pkcs7_func (void)
{
#ifdef ENABLE_PKCS7
gboolean ret;
g_autofree gchar *fw_fail = NULL;
g_autofree gchar *fw_pass = NULL;
g_autofree gchar *pki_dir = NULL;
g_autofree gchar *sig_fn = NULL;
g_autofree gchar *sig_fn2 = NULL;
g_autoptr(FuKeyring) keyring = NULL;
g_autoptr(FuKeyringResult) result_fail = NULL;
g_autoptr(FuKeyringResult) result_pass = NULL;
g_autoptr(GBytes) blob_fail = NULL;
g_autoptr(GBytes) blob_pass = NULL;
g_autoptr(GBytes) blob_sig = NULL;
g_autoptr(GBytes) blob_sig2 = NULL;
g_autoptr(GError) error = NULL;
/* add keys to keyring */
keyring = fu_keyring_pkcs7_new ();
ret = fu_keyring_setup (keyring, &error);
g_assert_no_error (error);
g_assert_true (ret);
pki_dir = fu_test_get_filename (TESTDATADIR_SRC, "pki");
g_assert_nonnull (pki_dir);
ret = fu_keyring_add_public_keys (keyring, pki_dir, &error);
g_assert_no_error (error);
g_assert_true (ret);
/* verify with a signature from the old LVFS */
fw_pass = fu_test_get_filename (TESTDATADIR_SRC, "colorhug/firmware.bin");
g_assert_nonnull (fw_pass);
blob_pass = fu_common_get_contents_bytes (fw_pass, &error);
g_assert_no_error (error);
g_assert_nonnull (blob_pass);
sig_fn = fu_test_get_filename (TESTDATADIR_SRC, "colorhug/firmware.bin.p7b");
g_assert_nonnull (sig_fn);
blob_sig = fu_common_get_contents_bytes (sig_fn, &error);
g_assert_no_error (error);
g_assert_nonnull (blob_sig);
result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig,
FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS,
&error);
g_assert_no_error (error);
g_assert_nonnull (result_pass);
g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), >= , 1502871248);
g_assert_cmpstr (fu_keyring_result_get_authority (result_pass), == , "O=Linux Vendor Firmware Project,CN=LVFS CA");
/* verify will fail with a self-signed signature */
sig_fn2 = fu_test_get_filename (TESTDATADIR_DST, "colorhug/firmware.bin.p7c");
g_assert_nonnull (sig_fn2);
blob_sig2 = fu_common_get_contents_bytes (sig_fn2, &error);
g_assert_no_error (error);
g_assert_nonnull (blob_sig2);
result_fail = fu_keyring_verify_data (keyring, blob_pass, blob_sig2,
FU_KEYRING_VERIFY_FLAG_NONE, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID);
g_assert_null (result_fail);
g_clear_error (&error);
/* verify will fail with valid signature and different data */
fw_fail = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab");
g_assert_nonnull (fw_fail);
blob_fail = fu_common_get_contents_bytes (fw_fail, &error);
g_assert_no_error (error);
g_assert_nonnull (blob_fail);
result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig,
FU_KEYRING_VERIFY_FLAG_NONE, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID);
g_assert_null (result_fail);
g_clear_error (&error);
#else
g_test_skip ("no GnuTLS support enabled");
#endif
}
static void
fu_keyring_pkcs7_self_signed_func (void)
{
#ifdef ENABLE_PKCS7
gboolean ret;
g_autoptr(FuKeyring) kr = NULL;
g_autoptr(FuKeyringResult) kr_result = NULL;
g_autoptr(GBytes) payload = NULL;
g_autoptr(GBytes) signature = NULL;
g_autoptr(GError) error = NULL;
#ifndef HAVE_GNUTLS_3_6_0
/* required to create the private key correctly */
g_test_skip ("GnuTLS version too old");
return;
#endif
/* create detached signature and verify */
kr = fu_keyring_pkcs7_new ();
ret = fu_keyring_setup (kr, &error);
g_assert_no_error (error);
g_assert_true (ret);
payload = fu_common_get_contents_bytes ("/etc/machine-id", &error);
g_assert_no_error (error);
g_assert_nonnull (payload);
signature = fu_keyring_sign_data (kr, payload, FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP, &error);
g_assert_no_error (error);
g_assert_nonnull (signature);
ret = fu_common_set_contents_bytes ("/tmp/test.p7b", signature, &error);
g_assert_no_error (error);
g_assert_true (ret);
kr_result = fu_keyring_verify_data (kr, payload, signature,
FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT, &error);
g_assert_no_error (error);
g_assert_nonnull (kr_result);
#else
g_test_skip ("no GnuTLS support enabled");
#endif
}
static void
fu_common_firmware_builder_func (void)
{
const gchar *data;
g_autofree gchar *archive_fn = NULL;
g_autoptr(GBytes) archive_blob = NULL;
g_autoptr(GBytes) firmware_blob = NULL;
g_autoptr(GError) error = NULL;
/* get test file */
archive_fn = fu_test_get_filename (TESTDATADIR, "builder/firmware.tar");
g_assert (archive_fn != NULL);
archive_blob = fu_common_get_contents_bytes (archive_fn, &error);
g_assert_no_error (error);
g_assert (archive_blob != NULL);
/* generate the firmware */
firmware_blob = fu_common_firmware_builder (archive_blob,
"startup.sh",
"firmware.bin",
&error);
if (firmware_blob == NULL) {
if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_PERMISSION_DENIED)) {
g_test_skip ("Missing permissions to create namespace in container");
return;
}
if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
g_test_skip ("User namespaces not supported in container");
return;
}
g_assert_no_error (error);
}
/* check it */
data = g_bytes_get_data (firmware_blob, NULL);
g_assert_cmpstr (data, ==, "xobdnas eht ni gninnur");
}
static void
fu_test_stdout_cb (const gchar *line, gpointer user_data)
{
guint *lines = (guint *) user_data;
g_debug ("got '%s'", line);
(*lines)++;
}
static gboolean
_open_cb (GObject *device, GError **error)
{
g_assert_cmpstr (g_object_get_data (device, "state"), ==, "closed");
g_object_set_data (device, "state", (gpointer) "opened");
return TRUE;
}
static gboolean
_close_cb (GObject *device, GError **error)
{
g_assert_cmpstr (g_object_get_data (device, "state"), ==, "opened");
g_object_set_data (device, "state", (gpointer) "closed-on-unref");
return TRUE;
}
static void
fu_device_locker_func (void)
{
g_autoptr(FuDeviceLocker) locker = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GObject) device = g_object_new (G_TYPE_OBJECT, NULL);
g_object_set_data (device, "state", (gpointer) "closed");
locker = fu_device_locker_new_full (device, _open_cb, _close_cb, &error);
g_assert_no_error (error);
g_assert_nonnull (locker);
g_clear_object (&locker);
g_assert_cmpstr (g_object_get_data (device, "state"), ==, "closed-on-unref");
}
static gboolean
_fail_open_cb (GObject *device, GError **error)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "fail");
return FALSE;
}
static gboolean
_fail_close_cb (GObject *device, GError **error)
{
g_assert_not_reached ();
return TRUE;
}
static void
fu_device_locker_fail_func (void)
{
g_autoptr(FuDeviceLocker) locker = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GObject) device = g_object_new (G_TYPE_OBJECT, NULL);
locker = fu_device_locker_new_full (device, _fail_open_cb, _fail_close_cb, &error);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
g_assert_null (locker);
}
static void
fu_common_spawn_func (void)
{
gboolean ret;
guint lines = 0;
g_autoptr(GError) error = NULL;
g_autofree gchar *fn = NULL;
const gchar *argv[3] = { "replace", "test", NULL };
fn = fu_test_get_filename (TESTDATADIR, "spawn.sh");
g_assert (fn != NULL);
argv[0] = fn;
ret = fu_common_spawn_sync (argv,
fu_test_stdout_cb, &lines, 0, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (lines, ==, 6);
}
static void
fu_common_spawn_timeout_func (void)
{
gboolean ret;
guint lines = 0;
g_autoptr(GError) error = NULL;
g_autofree gchar *fn = NULL;
const gchar *argv[3] = { "replace", "test", NULL };
fn = fu_test_get_filename (TESTDATADIR, "spawn.sh");
g_assert (fn != NULL);
argv[0] = fn;
ret = fu_common_spawn_sync (argv, fu_test_stdout_cb, &lines, 50, NULL, &error);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_assert (!ret);
g_assert_cmpint (lines, ==, 1);
}
static void
fu_progressbar_func (void)
{
g_autoptr(FuProgressbar) progressbar = fu_progressbar_new ();
fu_progressbar_set_length_status (progressbar, 20);
fu_progressbar_set_length_percentage (progressbar, 50);
g_print ("\n");
for (guint i = 0; i < 100; i++) {
fu_progressbar_update (progressbar, FWUPD_STATUS_DECOMPRESSING, i);
g_usleep (10000);
}
fu_progressbar_update (progressbar, FWUPD_STATUS_IDLE, 0);
for (guint i = 0; i < 100; i++) {
guint pc = (i > 25 && i < 75) ? 0 : i;
fu_progressbar_update (progressbar, FWUPD_STATUS_LOADING, pc);
g_usleep (10000);
}
fu_progressbar_update (progressbar, FWUPD_STATUS_IDLE, 0);
for (guint i = 0; i < 5000; i++) {
fu_progressbar_update (progressbar, FWUPD_STATUS_LOADING, 0);
g_usleep (1000);
}
fu_progressbar_update (progressbar, FWUPD_STATUS_IDLE, 0);
}
static void
fu_common_endian_func (void)
{
guint8 buf[2];
fu_common_write_uint16 (buf, 0x1234, G_LITTLE_ENDIAN);
g_assert_cmpint (buf[0], ==, 0x34);
g_assert_cmpint (buf[1], ==, 0x12);
g_assert_cmpint (fu_common_read_uint16 (buf, G_LITTLE_ENDIAN), ==, 0x1234);
fu_common_write_uint16 (buf, 0x1234, G_BIG_ENDIAN);
g_assert_cmpint (buf[0], ==, 0x12);
g_assert_cmpint (buf[1], ==, 0x34);
g_assert_cmpint (fu_common_read_uint16 (buf, G_BIG_ENDIAN), ==, 0x1234);
}
static GBytes *
_build_cab (GCabCompression compression, ...)
{
#ifdef HAVE_GCAB_1_0
gboolean ret;
va_list args;
g_autoptr(GCabCabinet) cabinet = NULL;
g_autoptr(GCabFolder) cabfolder = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GOutputStream) op = NULL;
/* create a new archive */
cabinet = gcab_cabinet_new ();
cabfolder = gcab_folder_new (compression);
ret = gcab_cabinet_add_folder (cabinet, cabfolder, &error);
g_assert_no_error (error);
g_assert (ret);
/* add each file */
va_start (args, compression);
do {
const gchar *fn;
const gchar *text;
g_autoptr(GCabFile) cabfile = NULL;
g_autoptr(GBytes) blob = NULL;
/* get filename */
fn = va_arg (args, const gchar *);
if (fn == NULL)
break;
/* get contents */
text = va_arg (args, const gchar *);
if (text == NULL)
break;
g_debug ("creating %s with %s", fn, text);
/* add a GCabFile to the cabinet */
blob = g_bytes_new_static (text, strlen (text));
cabfile = gcab_file_new_with_bytes (fn, blob);
ret = gcab_folder_add_file (cabfolder, cabfile, FALSE, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
} while (TRUE);
va_end (args);
/* write the archive to a blob */
op = g_memory_output_stream_new_resizable ();
ret = gcab_cabinet_write_simple (cabinet, op, NULL, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
ret = g_output_stream_close (op, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (op));
#else
return NULL;
#endif
}
static void
_plugin_composite_device_added_cb (FuPlugin *plugin, FuDevice *device, gpointer user_data)
{
GPtrArray *devices = (GPtrArray *) user_data;
g_ptr_array_add (devices, g_object_ref (device));
}
static void
fu_plugin_composite_func (void)
{
GError *error = NULL;
gboolean ret;
g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE);
g_autoptr(FuPlugin) plugin = fu_plugin_new ();
g_autoptr(GBytes) blob = NULL;
g_autoptr(GPtrArray) components = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GPtrArray) install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
g_autoptr(XbSilo) silo_empty = xb_silo_new ();
g_autoptr(XbSilo) silo = NULL;
/* no metadata in daemon */
fu_engine_set_silo (engine, silo_empty);
/* create CAB file */
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <provides>\n"
" <firmware type=\"flashed\">b585990a-003e-5270-89d5-3705a17f9a43</firmware>\n"
" </provides>\n"
" <releases>\n"
" <release version=\"1.2.3\"/>\n"
" </releases>\n"
"</component>",
"acme.module1.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware.module1</id>\n"
" <provides>\n"
" <firmware type=\"flashed\">7fddead7-12b5-4fb9-9fa0-6d30305df755</firmware>\n"
" </provides>\n"
" <releases>\n"
" <release version=\"2\"/>\n"
" </releases>\n"
" <custom>\n"
" <value key=\"LVFS::VersionFormat\">plain</value>\n"
" </custom>\n"
"</component>",
"acme.module2.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware.module2</id>\n"
" <provides>\n"
" <firmware type=\"flashed\">b8fe6b45-8702-4bcd-8120-ef236caac76f</firmware>\n"
" </provides>\n"
" <releases>\n"
" <release version=\"11\"/>\n"
" </releases>\n"
" <custom>\n"
" <value key=\"LVFS::VersionFormat\">plain</value>\n"
" </custom>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 10240, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
components = xb_silo_query (silo, "components/component", 0, &error);
g_assert_no_error (error);
g_assert_nonnull (components);
g_assert_cmpint (components->len, ==, 3);
/* set up dummy plugin */
g_setenv ("FWUPD_PLUGIN_TEST", "composite", TRUE);
ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error);
g_assert_no_error (error);
g_assert_true (ret);
fu_engine_add_plugin (engine, plugin);
ret = fu_plugin_runner_startup (plugin, &error);
g_assert_no_error (error);
g_assert_true (ret);
devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
g_signal_connect (plugin, "device-added",
G_CALLBACK (_plugin_composite_device_added_cb),
devices);
ret = fu_plugin_runner_coldplug (plugin, &error);
g_assert_no_error (error);
g_assert_true (ret);
/* check we found all composite devices */
g_assert_cmpint (devices->len, ==, 3);
for (guint i = 0; i < devices->len; i++) {
FuDevice *device = g_ptr_array_index (devices, i);
fu_engine_add_device (engine, device);
if (g_strcmp0 (fu_device_get_id (device),
"08d460be0f1f9f128413f816022a6439e0078018") == 0) {
g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.2");
} else if (g_strcmp0 (fu_device_get_id (device),
"c0a0a4aa6480ac28eea1ce164fbb466ca934e1ff") == 0) {
g_assert_cmpstr (fu_device_get_version (device), ==, "1");
g_assert_nonnull (fu_device_get_parent (device));
} else if (g_strcmp0 (fu_device_get_id (device),
"bf455e9f371d2608d1cb67660fd2b335d3f6ef73") == 0) {
g_assert_cmpstr (fu_device_get_version (device), ==, "10");
g_assert_nonnull (fu_device_get_parent (device));
}
}
/* produce install tasks */
for (guint i = 0; i < components->len; i++) {
XbNode *component = g_ptr_array_index (components, i);
/* do any devices pass the requirements */
for (guint j = 0; j < devices->len; j++) {
FuDevice *device = g_ptr_array_index (devices, j);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error_local = NULL;
/* is this component valid for the device */
task = fu_install_task_new (device, component);
if (!fu_engine_check_requirements (engine,
task,
0,
&error_local)) {
g_debug ("requirement on %s:%s failed: %s",
fu_device_get_id (device),
xb_node_query_text (component, "id", NULL),
error_local->message);
continue;
}
g_ptr_array_add (install_tasks, g_steal_pointer (&task));
}
}
g_assert_cmpint (install_tasks->len, ==, 3);
/* install the cab */
ret = fu_engine_install_tasks (engine,
install_tasks,
blob,
FWUPD_DEVICE_FLAG_NONE,
&error);
g_assert_no_error (error);
g_assert_true (ret);
/* verify everything upgraded */
for (guint i = 0; i < devices->len; i++) {
FuDevice *device = g_ptr_array_index (devices, i);
const gchar *metadata;
if (g_strcmp0 (fu_device_get_id (device),
"08d460be0f1f9f128413f816022a6439e0078018") == 0) {
g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3");
} else if (g_strcmp0 (fu_device_get_id (device),
"c0a0a4aa6480ac28eea1ce164fbb466ca934e1ff") == 0) {
g_assert_cmpstr (fu_device_get_version (device), ==, "2");
} else if (g_strcmp0 (fu_device_get_id (device),
"bf455e9f371d2608d1cb67660fd2b335d3f6ef73") == 0) {
g_assert_cmpstr (fu_device_get_version (device), ==, "11");
}
/* verify prepare and cleanup ran on all devices */
metadata = fu_device_get_metadata (device, "frimbulator");
g_assert_cmpstr (metadata, ==, "1");
metadata = fu_device_get_metadata (device, "frombulator");
g_assert_cmpstr (metadata, ==, "1");
}
}
static void
fu_common_store_cab_func (void)
{
GBytes *blob_tmp;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbNode) csum = NULL;
g_autoptr(XbNode) rel = NULL;
g_autoptr(XbNode) req = NULL;
g_autoptr(XbSilo) silo = NULL;
/* create silo */
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <name>ACME Firmware</name>\n"
" <provides>\n"
" <firmware type=\"flashed\">ae56e3fb-6528-5bc4-8b03-012f124075d7</firmware>\n"
" </provides>\n"
" <releases>\n"
" <release version=\"1.2.3\" date=\"2017-09-06\">\n"
" <size type=\"installed\">5</size>\n"
" <checksum filename=\"firmware.dfu\" target=\"content\" type=\"sha1\">7c211433f02071597741e6ff5a8ea34789abbf43</checksum>\n"
" <description><p>We fixed things</p></description>\n"
" </release>\n"
" </releases>\n"
" <requires>\n"
" <id compare=\"ge\" version=\"1.0.1\">org.freedesktop.fwupd</id>\n"
" </requires>\n"
"</component>",
"firmware.dfu", "world",
"firmware.dfu.asc", "signature",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 10240, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
/* verify */
component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
rel = xb_node_query_first (component, "releases/release", &error);
g_assert_no_error (error);
g_assert_nonnull (rel);
g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3");
csum = xb_node_query_first (rel, "checksum[@target='content']", &error);
g_assert_nonnull (csum);
g_assert_cmpstr (xb_node_get_text (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43");
blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu)");
g_assert_nonnull (blob_tmp);
blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu.asc)");
g_assert_nonnull (blob_tmp);
req = xb_node_query_first (component, "requires/id", &error);
g_assert_no_error (error);
g_assert_nonnull (req);
}
static void
fu_common_store_cab_unsigned_func (void)
{
GBytes *blob_tmp;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbNode) csum = NULL;
g_autoptr(XbNode) rel = NULL;
g_autoptr(XbSilo) silo = NULL;
/* create silo */
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\"/>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 10240, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
/* verify */
component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
rel = xb_node_query_first (component, "releases/release", &error);
g_assert_no_error (error);
g_assert_nonnull (rel);
g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3");
csum = xb_node_query_first (rel, "checksum[@target='content']", &error);
g_assert_null (csum);
blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)");
g_assert_nonnull (blob_tmp);
blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin.asc)");
g_assert_null (blob_tmp);
}
static void
fu_common_store_cab_folder_func (void)
{
GBytes *blob_tmp;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbNode) rel = NULL;
g_autoptr(XbSilo) silo = NULL;
/* create silo */
blob = _build_cab (GCAB_COMPRESSION_NONE,
"lvfs\\acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\"/>\n"
" </releases>\n"
"</component>",
"lvfs\\firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 10240, &error);
g_assert_no_error (error);
g_assert_nonnull (silo);
/* verify */
component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error);
g_assert_no_error (error);
g_assert_nonnull (component);
rel = xb_node_query_first (component, "releases/release", &error);
g_assert_no_error (error);
g_assert_nonnull (rel);
g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3");
blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)");
g_assert_nonnull (blob_tmp);
}
static void
fu_common_store_cab_error_no_metadata_func (void)
{
g_autoptr(XbSilo) silo = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"foo.txt", "hello",
"bar.txt", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 10240, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert_null (silo);
}
static void
fu_common_store_cab_error_wrong_size_func (void)
{
g_autoptr(XbSilo) silo = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\">\n"
" <size type=\"installed\">7004701</size>\n"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"sha1\">deadbeef</checksum>\n"
" </release>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 10240, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert_null (silo);
}
static void
fu_common_store_cab_error_missing_file_func (void)
{
g_autoptr(XbSilo) silo = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\">\n"
" <checksum filename=\"firmware.dfu\" target=\"content\"/>\n"
" </release>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 10240, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert_null (silo);
}
static void
fu_common_store_cab_error_size_func (void)
{
g_autoptr(XbSilo) silo = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\"/>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 123, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert_null (silo);
}
static void
fu_common_store_cab_error_wrong_checksum_func (void)
{
g_autoptr(XbSilo) silo = NULL;
g_autoptr(GBytes) blob = NULL;
g_autoptr(GError) error = NULL;
blob = _build_cab (GCAB_COMPRESSION_NONE,
"acme.metainfo.xml",
"<component type=\"firmware\">\n"
" <id>com.acme.example.firmware</id>\n"
" <releases>\n"
" <release version=\"1.2.3\">\n"
" <checksum filename=\"firmware.bin\" target=\"content\" type=\"sha1\">deadbeef</checksum>\n"
" </release>\n"
" </releases>\n"
"</component>",
"firmware.bin", "world",
NULL);
if (blob == NULL) {
g_test_skip ("libgcab too old");
return;
}
silo = fu_common_cab_build_silo (blob, 10240, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert_null (silo);
}
static gboolean
fu_device_poll_cb (FuDevice *device, GError **error)
{
guint64 cnt = fu_device_get_metadata_integer (device, "cnt");
g_debug ("poll cnt=%" G_GUINT64_FORMAT, cnt);
fu_device_set_metadata_integer (device, "cnt", cnt + 1);
return TRUE;
}
static void
fu_device_poll_func (void)
{
g_autoptr(FuDevice) device = fu_device_new ();
FuDeviceClass *klass = FU_DEVICE_GET_CLASS (device);
guint cnt;
/* set up a 10ms poll */
klass->poll = fu_device_poll_cb;
fu_device_set_metadata_integer (device, "cnt", 0);
fu_device_set_poll_interval (device, 10);
fu_test_loop_run_with_timeout (100);
fu_test_loop_quit ();
cnt = fu_device_get_metadata_integer (device, "cnt");
g_assert_cmpint (cnt, >=, 8);
/* disable the poll */
fu_device_set_poll_interval (device, 0);
fu_test_loop_run_with_timeout (100);
fu_test_loop_quit ();
g_assert_cmpint (fu_device_get_metadata_integer (device, "cnt"), ==, cnt);
}
static void
fu_device_incorporate_func (void)
{
g_autoptr(FuDevice) device = fu_device_new ();
g_autoptr(FuDevice) donor = fu_device_new ();
/* set up donor device */
fu_device_set_alternate_id (donor, "alt-id");
fu_device_set_equivalent_id (donor, "equiv-id");
fu_device_set_metadata (donor, "test", "me");
fu_device_set_metadata (donor, "test2", "me");
/* base properties */
fu_device_add_flag (donor, FWUPD_DEVICE_FLAG_REQUIRE_AC);
fu_device_set_created (donor, 123);
fu_device_set_modified (donor, 456);
fu_device_add_icon (donor, "computer");
/* existing properties */
fu_device_set_equivalent_id (device, "DO_NOT_OVERWRITE");
fu_device_set_metadata (device, "test2", "DO_NOT_OVERWRITE");
fu_device_set_modified (device, 789);
/* incorporate properties from donor to device */
fu_device_incorporate (device, donor);
g_assert_cmpstr (fu_device_get_alternate_id (device), ==, "alt-id");
g_assert_cmpstr (fu_device_get_equivalent_id (device), ==, "DO_NOT_OVERWRITE");
g_assert_cmpstr (fu_device_get_metadata (device, "test"), ==, "me");
g_assert_cmpstr (fu_device_get_metadata (device, "test2"), ==, "DO_NOT_OVERWRITE");
g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC));
g_assert_cmpint (fu_device_get_created (device), ==, 123);
g_assert_cmpint (fu_device_get_modified (device), ==, 789);
g_assert_cmpint (fu_device_get_icons(device)->len, ==, 1);
}
static void
fu_chunk_func (void)
{
g_autofree gchar *chunked1_str = NULL;
g_autofree gchar *chunked2_str = NULL;
g_autofree gchar *chunked3_str = NULL;
g_autofree gchar *chunked4_str = NULL;
g_autoptr(GPtrArray) chunked1 = NULL;
g_autoptr(GPtrArray) chunked2 = NULL;
g_autoptr(GPtrArray) chunked3 = NULL;
g_autoptr(GPtrArray) chunked4 = NULL;
chunked3 = fu_chunk_array_new ((const guint8 *) "123456", 6, 0x0, 3, 3);
chunked3_str = fu_chunk_array_to_string (chunked3);
g_print ("\n%s", chunked3_str);
g_assert_cmpstr (chunked3_str, ==, "#00: page:00 addr:0000 len:03 123\n"
"#01: page:01 addr:0000 len:03 456\n");
chunked4 = fu_chunk_array_new ((const guint8 *) "123456", 6, 0x4, 4, 4);
chunked4_str = fu_chunk_array_to_string (chunked4);
g_print ("\n%s", chunked4_str);
g_assert_cmpstr (chunked4_str, ==, "#00: page:01 addr:0000 len:04 1234\n"
"#01: page:02 addr:0000 len:02 56\n");
chunked1 = fu_chunk_array_new ((const guint8 *) "0123456789abcdef", 16, 0x0, 10, 4);
chunked1_str = fu_chunk_array_to_string (chunked1);
g_print ("\n%s", chunked1_str);
g_assert_cmpstr (chunked1_str, ==, "#00: page:00 addr:0000 len:04 0123\n"
"#01: page:00 addr:0004 len:04 4567\n"
"#02: page:00 addr:0008 len:02 89\n"
"#03: page:01 addr:0000 len:04 abcd\n"
"#04: page:01 addr:0004 len:02 ef\n");
chunked2 = fu_chunk_array_new ((const guint8 *) "XXXXXXYYYYYYZZZZZZ", 18, 0x0, 6, 4);
chunked2_str = fu_chunk_array_to_string (chunked2);
g_print ("\n%s", chunked2_str);
g_assert_cmpstr (chunked2_str, ==, "#00: page:00 addr:0000 len:04 XXXX\n"
"#01: page:00 addr:0004 len:02 XX\n"
"#02: page:01 addr:0000 len:04 YYYY\n"
"#03: page:01 addr:0004 len:02 YY\n"
"#04: page:02 addr:0000 len:04 ZZZZ\n"
"#05: page:02 addr:0004 len:02 ZZ\n");
}
static void
fu_common_strstrip_func (void)
{
struct {
const gchar *old;
const gchar *new;
} map[] = {
{ "same", "same" },
{ " leading", "leading" },
{ "tailing ", "tailing" },
{ " b ", "b" },
{ " ", "" },
{ NULL, NULL }
};
for (guint i = 0; map[i].old != NULL; i++) {
g_autofree gchar *tmp = fu_common_strstrip (map[i].old);
g_assert_cmpstr (tmp, ==, map[i].new);
}
}
static void
fu_common_version_func (void)
{
guint i;
struct {
guint32 val;
const gchar *ver;
FwupdVersionFormat flags;
} version_from_uint32[] = {
{ 0x0, "0.0.0.0", FWUPD_VERSION_FORMAT_QUAD },
{ 0xff, "0.0.0.255", FWUPD_VERSION_FORMAT_QUAD },
{ 0xff01, "0.0.255.1", FWUPD_VERSION_FORMAT_QUAD },
{ 0xff0001, "0.255.0.1", FWUPD_VERSION_FORMAT_QUAD },
{ 0xff000100, "255.0.1.0", FWUPD_VERSION_FORMAT_QUAD },
{ 0x0, "0.0.0", FWUPD_VERSION_FORMAT_TRIPLET },
{ 0xff, "0.0.255", FWUPD_VERSION_FORMAT_TRIPLET },
{ 0xff01, "0.0.65281", FWUPD_VERSION_FORMAT_TRIPLET },
{ 0xff0001, "0.255.1", FWUPD_VERSION_FORMAT_TRIPLET },
{ 0xff000100, "255.0.256", FWUPD_VERSION_FORMAT_TRIPLET },
{ 0x0, "0", FWUPD_VERSION_FORMAT_NUMBER },
{ 0xff000100, "4278190336", FWUPD_VERSION_FORMAT_NUMBER },
{ 0x0, "11.0.0.0", FWUPD_VERSION_FORMAT_INTEL_ME },
{ 0xffffffff, "18.31.255.65535", FWUPD_VERSION_FORMAT_INTEL_ME },
{ 0x0b32057a, "11.11.50.1402", FWUPD_VERSION_FORMAT_INTEL_ME },
{ 0xb8320d84, "11.8.50.3460", FWUPD_VERSION_FORMAT_INTEL_ME2 },
{ 0, NULL }
};
struct {
guint16 val;
const gchar *ver;
FwupdVersionFormat flags;
} version_from_uint16[] = {
{ 0x0, "0.0", FWUPD_VERSION_FORMAT_PAIR },
{ 0xff, "0.255", FWUPD_VERSION_FORMAT_PAIR },
{ 0xff01, "255.1", FWUPD_VERSION_FORMAT_PAIR },
{ 0x0, "0.0", FWUPD_VERSION_FORMAT_BCD },
{ 0x0110, "1.10", FWUPD_VERSION_FORMAT_BCD },
{ 0x9999, "99.99", FWUPD_VERSION_FORMAT_BCD },
{ 0x0, "0", FWUPD_VERSION_FORMAT_NUMBER },
{ 0x1234, "4660", FWUPD_VERSION_FORMAT_NUMBER },
{ 0, NULL }
};
struct {
const gchar *old;
const gchar *new;
} version_parse[] = {
{ "0", "0" },
{ "0x1a", "0.0.26" },
{ "257", "0.0.257" },
{ "1.2.3", "1.2.3" },
{ "0xff0001", "0.255.1" },
{ "16711681", "0.255.1" },
{ "20150915", "20150915" },
{ "dave", "dave" },
{ "0x1x", "0x1x" },
{ NULL, NULL }
};
/* check version conversion */
for (i = 0; version_from_uint32[i].ver != NULL; i++) {
g_autofree gchar *ver = NULL;
ver = fu_common_version_from_uint32 (version_from_uint32[i].val,
version_from_uint32[i].flags);
g_assert_cmpstr (ver, ==, version_from_uint32[i].ver);
}
for (i = 0; version_from_uint16[i].ver != NULL; i++) {
g_autofree gchar *ver = NULL;
ver = fu_common_version_from_uint16 (version_from_uint16[i].val,
version_from_uint16[i].flags);
g_assert_cmpstr (ver, ==, version_from_uint16[i].ver);
}
/* check version parsing */
for (i = 0; version_parse[i].old != NULL; i++) {
g_autofree gchar *ver = NULL;
ver = fu_common_version_parse (version_parse[i].old);
g_assert_cmpstr (ver, ==, version_parse[i].new);
}
}
static void
fu_common_vercmp_func (void)
{
/* same */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("001.002.003", "001.002.003"), ==, 0);
/* same, not dotted decimal */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "0x1020003"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("0x10203", "0x10203"), ==, 0);
/* upgrade and downgrade */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.4"), <, 0);
g_assert_cmpint (fu_common_vercmp ("001.002.000", "001.002.009"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.2"), >, 0);
g_assert_cmpint (fu_common_vercmp ("001.002.009", "001.002.000"), >, 0);
/* unequal depth */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3.1"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3.1", "1.2.4"), <, 0);
/* mixed-alpha-numeric */
g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3a"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3b"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3b", "1.2.3a"), >, 0);
/* alpha version append */
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3a"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3"), >, 0);
/* alpha only */
g_assert_cmpint (fu_common_vercmp ("alpha", "alpha"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("alpha", "beta"), <, 0);
g_assert_cmpint (fu_common_vercmp ("beta", "alpha"), >, 0);
/* alpha-compare */
g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2a.3"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2b.3"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2b.3", "1.2a.3"), >, 0);
/* tilde is all-powerful */
g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3~rc1"), ==, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3"), <, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3~rc1"), >, 0);
g_assert_cmpint (fu_common_vercmp ("1.2.3~rc2", "1.2.3~rc1"), >, 0);
/* invalid */
g_assert_cmpint (fu_common_vercmp ("1", NULL), ==, G_MAXINT);
g_assert_cmpint (fu_common_vercmp (NULL, "1"), ==, G_MAXINT);
g_assert_cmpint (fu_common_vercmp (NULL, NULL), ==, G_MAXINT);
}
static void
fu_firmware_ihex_func (void)
{
const guint8 *data;
gboolean ret;
gsize len;
g_autofree gchar *filename_hex = NULL;
g_autofree gchar *filename_ref = NULL;
g_autofree gchar *str = NULL;
g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new ();
g_autoptr(GBytes) data_file = NULL;
g_autoptr(GBytes) data_fw = NULL;
g_autoptr(GBytes) data_hex = NULL;
g_autoptr(GBytes) data_ref = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GFile) file_ref = NULL;
g_autoptr(GFile) file_hex = NULL;
/* load a Intel hex32 file */
filename_hex = fu_test_get_filename (TESTDATADIR, "firmware.hex");
g_assert (filename_hex != NULL);
file_hex = g_file_new_for_path (filename_hex);
data_file = g_file_load_bytes (file_hex, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (data_file != NULL);
ret = fu_firmware_parse (firmware, data_file, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
data_fw = fu_firmware_get_image_default_bytes (firmware, &error);
g_assert_no_error (error);
g_assert_nonnull (data_fw);
g_assert_cmpint (g_bytes_get_size (data_fw), ==, 136);
/* did we match the reference file? */
filename_ref = fu_test_get_filename (TESTDATADIR, "firmware.bin");
g_assert (filename_ref != NULL);
file_ref = g_file_new_for_path (filename_ref);
data_ref = g_file_load_bytes (file_ref, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (data_ref != NULL);
ret = fu_common_bytes_compare (data_fw, data_ref, &error);
g_assert_no_error (error);
g_assert_true (ret);
/* export a ihex file (which will be slightly different due to
* non-continous regions being expanded */
data_hex = fu_firmware_write (firmware, &error);
g_assert_no_error (error);
g_assert (data_hex != NULL);
data = g_bytes_get_data (data_hex, &len);
str = g_strndup ((const gchar *) data, len);
g_assert_cmpstr (str, ==,
":104000003DEF20F000000000FACF01F0FBCF02F0FE\n"
":10401000E9CF03F0EACF04F0E1CF05F0E2CF06F0FC\n"
":10402000D9CF07F0DACF08F0F3CF09F0F4CF0AF0D8\n"
":10403000F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF078\n"
":104040000EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FF68\n"
":104050000AC0F4FF09C0F3FF08C0DAFF07C0D9FFA8\n"
":1040600006C0E2FF05C0E1FF04C0EAFF03C0E9FFAC\n"
":1040700002C0FBFF01C0FAFF11003FEF20F000017A\n"
":0840800042EF20F03DEF20F0BB\n"
":00000001FF\n");
}
static void
fu_firmware_ihex_signed_func (void)
{
const guint8 *data;
gboolean ret;
gsize len;
g_autofree gchar *filename_shex = NULL;
g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new ();
g_autoptr(GBytes) data_file = NULL;
g_autoptr(GBytes) data_fw = NULL;
g_autoptr(GBytes) data_sig = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GFile) file_hex = NULL;
/* load a signed Intel hex32 file */
filename_shex = fu_test_get_filename (TESTDATADIR, "firmware.shex");
g_assert (filename_shex != NULL);
file_hex = g_file_new_for_path (filename_shex);
data_file = g_file_load_bytes (file_hex, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (data_file != NULL);
ret = fu_firmware_parse (firmware, data_file, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
data_fw = fu_firmware_get_image_by_id_bytes (firmware, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (data_fw);
g_assert_cmpint (g_bytes_get_size (data_fw), ==, 136);
/* get the signed image */
data_sig = fu_firmware_get_image_by_id_bytes (firmware, "signature", &error);
g_assert_no_error (error);
g_assert_nonnull (data_sig);
data = g_bytes_get_data (data_sig, &len);
g_assert_cmpint (len, ==, 8);
g_assert (data != NULL);
g_assert_cmpint (memcmp (data, "deadbeef", 8), ==, 0);
}
static void
fu_firmware_ihex_offset_func (void)
{
const guint8 *data;
gboolean ret;
gsize len;
g_autofree gchar *str = NULL;
g_autoptr(FuFirmware) firmware = fu_ihex_firmware_new ();
g_autoptr(FuFirmware) firmware_verify = fu_ihex_firmware_new ();
g_autoptr(FuFirmwareImage) img_verify = NULL;
g_autoptr(FuFirmwareImage) img = NULL;
g_autoptr(GBytes) data_bin = NULL;
g_autoptr(GBytes) data_dummy = NULL;
g_autoptr(GBytes) data_verify = NULL;
g_autoptr(GError) error = NULL;
/* add a 4 byte image in high memory */
data_dummy = g_bytes_new_static ("foo", 4);
img = fu_firmware_image_new (data_dummy);
fu_firmware_image_set_addr (img, 0x80000000);
fu_firmware_add_image (firmware, img);
data_bin = fu_firmware_write (firmware, &error);
g_assert_no_error (error);
g_assert (data_bin != NULL);
data = g_bytes_get_data (data_bin, &len);
str = g_strndup ((const gchar *) data, len);
g_assert_cmpstr (str, ==,
":0200000480007A\n"
":04000000666F6F00B8\n"
":00000001FF\n");
/* check we can load it too */
ret = fu_firmware_parse (firmware_verify, data_bin, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
img_verify = fu_firmware_get_image_default (firmware_verify, &error);
g_assert_no_error (error);
g_assert (img_verify != NULL);
g_assert_cmpint (fu_firmware_image_get_addr (img_verify), ==, 0x80000000);
data_verify = fu_firmware_image_get_bytes (img_verify, &error);
g_assert_no_error (error);
g_assert (data_verify != NULL);
g_assert_cmpint (g_bytes_get_size (data_verify), ==, 0x4);
}
static void
fu_firmware_srec_func (void)
{
gboolean ret;
g_autofree gchar *filename_srec = NULL;
g_autofree gchar *filename_ref = NULL;
g_autoptr(FuFirmware) firmware = fu_srec_firmware_new ();
g_autoptr(GBytes) data_ref = NULL;
g_autoptr(GBytes) data_srec = NULL;
g_autoptr(GBytes) data_bin = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GFile) file_bin = NULL;
g_autoptr(GFile) file_srec = NULL;
filename_srec = fu_test_get_filename (TESTDATADIR, "firmware.srec");
g_assert (filename_srec != NULL);
file_srec = g_file_new_for_path (filename_srec);
data_srec = g_file_load_bytes (file_srec, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (data_srec != NULL);
ret = fu_firmware_parse (firmware, data_srec, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error (error);
g_assert (ret);
data_bin = fu_firmware_get_image_default_bytes (firmware, &error);
g_assert_no_error (error);
g_assert_nonnull (data_bin);
g_assert_cmpint (g_bytes_get_size (data_bin), ==, 136);
/* did we match the reference file? */
filename_ref = fu_test_get_filename (TESTDATADIR, "firmware.bin");
g_assert (filename_ref != NULL);
file_bin = g_file_new_for_path (filename_ref);
data_ref = g_file_load_bytes (file_bin, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (data_ref != NULL);
ret = fu_common_bytes_compare (data_bin, data_ref, &error);
g_assert_no_error (error);
g_assert_true (ret);
}
static void
fu_firmware_func (void)
{
g_autoptr(FuFirmware) firmware = fu_firmware_new ();
g_autoptr(FuFirmwareImage) img1 = fu_firmware_image_new (NULL);
g_autoptr(FuFirmwareImage) img2 = fu_firmware_image_new (NULL);
g_autoptr(FuFirmwareImage) img_id = NULL;
g_autoptr(FuFirmwareImage) img_idx = NULL;
g_autoptr(GError) error = NULL;
g_autofree gchar *str = NULL;
fu_firmware_image_set_addr (img1, 0x200);
fu_firmware_image_set_idx (img1, 13);
fu_firmware_image_set_id (img1, "primary");
fu_firmware_add_image (firmware, img1);
fu_firmware_image_set_addr (img2, 0x400);
fu_firmware_image_set_idx (img2, 23);
fu_firmware_image_set_id (img2, "secondary");
fu_firmware_add_image (firmware, img2);
img_id = fu_firmware_get_image_by_id (firmware, "NotGoingToExist", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert_null (img_id);
g_clear_error (&error);
img_id = fu_firmware_get_image_by_id (firmware, "primary", &error);
g_assert_no_error (error);
g_assert_nonnull (img_id);
g_assert_cmpint (fu_firmware_image_get_addr (img_id), ==, 0x200);
g_assert_cmpint (fu_firmware_image_get_idx (img_id), ==, 13);
g_assert_cmpstr (fu_firmware_image_get_id (img_id), ==, "primary");
img_idx = fu_firmware_get_image_by_idx (firmware, 123456, &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert_null (img_idx);
g_clear_error (&error);
img_idx = fu_firmware_get_image_by_idx (firmware, 23, &error);
g_assert_no_error (error);
g_assert_nonnull (img_idx);
g_assert_cmpint (fu_firmware_image_get_addr (img_idx), ==, 0x400);
g_assert_cmpint (fu_firmware_image_get_idx (img_idx), ==, 23);
g_assert_cmpstr (fu_firmware_image_get_id (img_idx), ==, "secondary");
str = fu_firmware_to_string (firmware);
g_assert_cmpstr (str, ==, "FuFirmware:\n"
" FuFirmwareImage:\n"
" ID: primary\n"
" Index: 0x000d\n"
" Address: 0x0200\n"
" FuFirmwareImage:\n"
" ID: secondary\n"
" Index: 0x0017\n"
" Address: 0x0400\n");
}
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
/* only critical and error are fatal */
g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
g_setenv ("FWUPD_DATADIR", TESTDATADIR_SRC, TRUE);
g_setenv ("FWUPD_PLUGINDIR", TESTDATADIR_SRC, TRUE);
g_setenv ("FWUPD_SYSCONFDIR", TESTDATADIR_SRC, TRUE);
g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR_SRC, TRUE);
g_setenv ("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE);
/* ensure empty tree */
fu_self_test_mkroot ();
/* tests go here */
if (g_test_slow ())
g_test_add_func ("/fwupd/progressbar", fu_progressbar_func);
g_test_add_func ("/fwupd/firmware", fu_firmware_func);
g_test_add_func ("/fwupd/firmware{ihex}", fu_firmware_ihex_func);
g_test_add_func ("/fwupd/firmware{ihex-offset}", fu_firmware_ihex_offset_func);
g_test_add_func ("/fwupd/firmware{ihex-signed}", fu_firmware_ihex_signed_func);
g_test_add_func ("/fwupd/firmware{srec}", fu_firmware_srec_func);
g_test_add_func ("/fwupd/archive{invalid}", fu_archive_invalid_func);
g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_func);
g_test_add_func ("/fwupd/engine{requirements-other-device}", fu_engine_requirements_other_device_func);
g_test_add_func ("/fwupd/device{incorporate}", fu_device_incorporate_func);
g_test_add_func ("/fwupd/device{poll}", fu_device_poll_func);
g_test_add_func ("/fwupd/device-locker{success}", fu_device_locker_func);
g_test_add_func ("/fwupd/device-locker{fail}", fu_device_locker_fail_func);
g_test_add_func ("/fwupd/device{metadata}", fu_device_metadata_func);
g_test_add_func ("/fwupd/device{open-refcount}", fu_device_open_refcount_func);
g_test_add_func ("/fwupd/device{version-format}", fu_device_version_format_func);
g_test_add_func ("/fwupd/device-list", fu_device_list_func);
g_test_add_func ("/fwupd/device-list{delay}", fu_device_list_delay_func);
g_test_add_func ("/fwupd/device-list{compatible}", fu_device_list_compatible_func);
g_test_add_func ("/fwupd/device-list{remove-chain}", fu_device_list_remove_chain_func);
g_test_add_func ("/fwupd/engine{device-unlock}", fu_engine_device_unlock_func);
g_test_add_func ("/fwupd/engine{history-success}", fu_engine_history_func);
g_test_add_func ("/fwupd/engine{history-error}", fu_engine_history_error_func);
if (g_test_slow ())
g_test_add_func ("/fwupd/device-list{replug-auto}", fu_device_list_replug_auto_func);
g_test_add_func ("/fwupd/device-list{replug-user}", fu_device_list_replug_user_func);
g_test_add_func ("/fwupd/engine{require-hwid}", fu_engine_require_hwid_func);
g_test_add_func ("/fwupd/engine{history-inherit}", fu_engine_history_inherit);
g_test_add_func ("/fwupd/engine{partial-hash}", fu_engine_partial_hash_func);
g_test_add_func ("/fwupd/engine{downgrade}", fu_engine_downgrade_func);
g_test_add_func ("/fwupd/engine{requirements-success}", fu_engine_requirements_func);
g_test_add_func ("/fwupd/engine{requirements-missing}", fu_engine_requirements_missing_func);
g_test_add_func ("/fwupd/engine{requirements-not-child}", fu_engine_requirements_child_func);
g_test_add_func ("/fwupd/engine{requirements-not-child-fail}", fu_engine_requirements_child_fail_func);
g_test_add_func ("/fwupd/engine{requirements-unsupported}", fu_engine_requirements_unsupported_func);
g_test_add_func ("/fwupd/engine{requirements-device}", fu_engine_requirements_device_func);
g_test_add_func ("/fwupd/engine{requirements-version-format}", fu_engine_requirements_version_format_func);
g_test_add_func ("/fwupd/engine{device-auto-parent}", fu_engine_device_parent_func);
g_test_add_func ("/fwupd/engine{device-priority}", fu_engine_device_priority_func);
g_test_add_func ("/fwupd/engine{install-duration}", fu_engine_install_duration_func);
g_test_add_func ("/fwupd/engine{generate-md}", fu_engine_generate_md_func);
g_test_add_func ("/fwupd/hwids", fu_hwids_func);
g_test_add_func ("/fwupd/smbios", fu_smbios_func);
g_test_add_func ("/fwupd/smbios3", fu_smbios3_func);
g_test_add_func ("/fwupd/history", fu_history_func);
g_test_add_func ("/fwupd/history{migrate}", fu_history_migrate_func);
g_test_add_func ("/fwupd/plugin-list", fu_plugin_list_func);
g_test_add_func ("/fwupd/plugin-list{depsolve}", fu_plugin_list_depsolve_func);
g_test_add_func ("/fwupd/plugin{delay}", fu_plugin_delay_func);
g_test_add_func ("/fwupd/plugin{module}", fu_plugin_module_func);
g_test_add_func ("/fwupd/plugin{quirks}", fu_plugin_quirks_func);
g_test_add_func ("/fwupd/plugin{quirks-performance}", fu_plugin_quirks_performance_func);
g_test_add_func ("/fwupd/plugin{quirks-device}", fu_plugin_quirks_device_func);
g_test_add_func ("/fwupd/plugin{composite}", fu_plugin_composite_func);
g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func);
g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func);
g_test_add_func ("/fwupd/keyring{pkcs7-self-signed}", fu_keyring_pkcs7_self_signed_func);
g_test_add_func ("/fwupd/plugin{build-hash}", fu_plugin_hash_func);
g_test_add_func ("/fwupd/chunk", fu_chunk_func);
g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func);
g_test_add_func ("/fwupd/common{version}", fu_common_version_func);
g_test_add_func ("/fwupd/common{vercmp}", fu_common_vercmp_func);
g_test_add_func ("/fwupd/common{strstrip}", fu_common_strstrip_func);
g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func);
g_test_add_func ("/fwupd/common{cab-success}", fu_common_store_cab_func);
g_test_add_func ("/fwupd/common{cab-success-unsigned}", fu_common_store_cab_unsigned_func);
g_test_add_func ("/fwupd/common{cab-success-folder}", fu_common_store_cab_folder_func);
g_test_add_func ("/fwupd/common{cab-error-no-metadata}", fu_common_store_cab_error_no_metadata_func);
g_test_add_func ("/fwupd/common{cab-error-wrong-size}", fu_common_store_cab_error_wrong_size_func);
g_test_add_func ("/fwupd/common{cab-error-wrong-checksum}", fu_common_store_cab_error_wrong_checksum_func);
g_test_add_func ("/fwupd/common{cab-error-missing-file}", fu_common_store_cab_error_missing_file_func);
g_test_add_func ("/fwupd/common{cab-error-size}", fu_common_store_cab_error_size_func);
g_test_add_func ("/fwupd/common{spawn)", fu_common_spawn_func);
g_test_add_func ("/fwupd/common{spawn-timeout)", fu_common_spawn_timeout_func);
g_test_add_func ("/fwupd/common{firmware-builder}", fu_common_firmware_builder_func);
return g_test_run ();
}