From: Andreas Reichel <
andreas.r...@siemens.com>
The new testcode initially provides tests for
* internal userspace API core functions
* external userspace API functions (libebgenv.a)
They are devided into the following test-suits:
* test_bgenv_init_retval.c, where partition probing must be
faked and disks must be simualted.
* test_probe_config_file.c, where the existence of environment
data is faked for simulated config partitions
* test_ebgenv_api_internal.c, core functions for userspace API
* test_ebgenv_api.c, library API functions for userspace
.travis-build.sh | 3 +
env/env_api_fat.c | 6 +-
include/test-interface.h | 4 +
tools/tests/Makefile.am | 56 ++-
tools/tests/fake_devices.c | 94 +++++
tools/tests/fake_devices.h | 28 ++
tools/tests/test_bgenv_init_retval.c | 100 +++++
tools/tests/test_ebgenv_api.c | 641 +++++++++++++++++++++++++++++
tools/tests/test_ebgenv_api_internal.c | 416 +++++++++++++++++++
tools/tests/test_main.c | 34 ++
tools/tests/test_probe_config_file.c | 202 +++++++++
tools/tests/test_probe_config_partitions.c | 99 +++++
12 files changed, 1673 insertions(+), 10 deletions(-)
create mode 100644 tools/tests/fake_devices.c
create mode 100644 tools/tests/fake_devices.h
create mode 100644 tools/tests/test_bgenv_init_retval.c
create mode 100644 tools/tests/test_ebgenv_api.c
create mode 100644 tools/tests/test_ebgenv_api_internal.c
create mode 100644 tools/tests/test_main.c
create mode 100644 tools/tests/test_probe_config_file.c
create mode 100644 tools/tests/test_probe_config_partitions.c
diff --git a/.travis-build.sh b/.travis-build.sh
index a7e6beb..d977385 100755
--- a/.travis-build.sh
+++ b/.travis-build.sh
@@ -115,6 +115,9 @@ case "$TARGET_EFFECTIVE" in
suppress+=" --suppress=unusedFunction:env/fatvars.c"
suppress+=" --suppress=unusedFunction:tools/tests/test_environment.c"
suppress+=" --suppress=unusedFunction:env/env_api_fat.c"
+ # Some functions are used by linker wrapping
+ suppress+=" --suppress=unusedFunction:tools/tests/test_probe_config_file.c"
+ suppress+=" --suppress=unusedFunction:tools/tests/test_ebgenv_api.c"
# EFI uses void* as ImageBase needed for further calculations
suppress+=" --suppress=arithOperationsOnVoidPointer:main.c"
diff --git a/env/env_api_fat.c b/env/env_api_fat.c
index a344fcb..8eb1454 100644
--- a/env/env_api_fat.c
+++ b/env/env_api_fat.c
@@ -20,7 +20,7 @@
bool bgenv_verbosity = false;
-static EBGENVKEY bgenv_str2enum(char *key)
+EBGENVKEY bgenv_str2enum(char *key)
{
if (strncmp(key, "kernelfile", strlen("kernelfile") + 1) == 0) {
return EBGENV_KERNELFILE;
@@ -120,8 +120,8 @@ bool write_env(CONFIG_PART *part, BG_ENVDATA *env)
return result;
}
-static CONFIG_PART config_parts[ENV_NUM_CONFIG_PARTS];
-static BG_ENVDATA envdata[ENV_NUM_CONFIG_PARTS];
+CONFIG_PART config_parts[ENV_NUM_CONFIG_PARTS];
+BG_ENVDATA envdata[ENV_NUM_CONFIG_PARTS];
bool bgenv_init()
{
diff --git a/include/test-interface.h b/include/test-interface.h
index 36b0a62..c220d14 100644
--- a/include/test-interface.h
+++ b/include/test-interface.h
@@ -15,11 +15,15 @@
#include "env_api.h"
+extern CONFIG_PART config_parts[ENV_NUM_CONFIG_PARTS];
+extern BG_ENVDATA envdata[ENV_NUM_CONFIG_PARTS];
+
bool read_env(CONFIG_PART *part, BG_ENVDATA *env);
bool write_env(CONFIG_PART *part, BG_ENVDATA *env);
bool probe_config_file(CONFIG_PART *cfgpart);
bool probe_config_partitions(CONFIG_PART *cfgparts);
bool mount_partition(CONFIG_PART *cfgpart);
+EBGENVKEY bgenv_str2enum(char *key);
#endif // __TEST_INTERFACE_H__
diff --git a/tools/tests/Makefile.am b/tools/tests/Makefile.am
index 30dbb85..fd49e06 100644
--- a/tools/tests/Makefile.am
+++ b/tools/tests/Makefile.am
@@ -12,13 +12,12 @@
OBJCOPY ?= objcopy
-AM_CPPFLAGS = \
+AM_CFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/swupdate-adapter \
-I$(top_srcdir)/tools \
- -I$(top_srcdir)/fff
-
-AM_CFLAGS = \
+ -I$(top_srcdir)/tools/tests \
+ -I$(top_srcdir)/fff \
-Wno-unused-parameter \
-Wmissing-prototypes \
-fshort-wchar \
@@ -26,11 +25,54 @@ AM_CFLAGS = \
-D_GNU_SOURCE \
-g
+libtest_env_api_fat_a_SRC = \
+ ../../env/env_api.c \
+ ../../env/env_api_fat.c \
+ ../../tools/ebgpart.c \
+ ../../env/env_config_file.c \
+ ../../env/env_config_partitions.c \
+ ../../env/env_disk_utils.c \
+ ../../env/uservars.c
+
CLEANFILES =
-test_api:
- ln -sf /bin/true test_api
+noinst_LIBRARIES = libtest_env_api_fat.a
+libtest_env_api_fat_a_SOURCES = $(libtest_env_api_fat_a_SRC)
+
+libenvapi_testlib_fat.a: libtest_env_api_fat.a
+ $(OBJCOPY) --weaken $^ $@
+
+check_PROGRAMS = test_bgenv_init_retval \
+ test_probe_config_partitions \
+ test_probe_config_file \
+ test_ebgenv_api_internal \
+ test_ebgenv_api
+
+FAT_TESTLIB=libenvapi_testlib_fat.a
+
+SRC_TEST_COMMON=test_main.c
+
+test_bgenv_init_retval_CFLAGS = $(AM_CFLAGS)
+test_bgenv_init_retval_SOURCES = test_bgenv_init_retval.c $(SRC_TEST_COMMON)
+test_bgenv_init_retval_LDADD = $(FAT_TESTLIB) $(LIBCHECK_LIBS)
+
+test_probe_config_partitions_CFLAGS = $(AM_CFLAGS)
+test_probe_config_partitions_SOURCES = test_probe_config_partitions.c \
+ fake_devices.c \
+ $(SRC_TEST_COMMON)
+test_probe_config_partitions_LDADD = $(FAT_TESTLIB) $(LIBCHECK_LIBS)
+
+test_probe_config_file_CFLAGS = $(AM_CFLAGS) -Wl,--wrap=probe_config_file
+test_probe_config_file_SOURCES = test_probe_config_file.c fake_devices.c \
+ $(SRC_TEST_COMMON)
+test_probe_config_file_LDADD = $(FAT_TESTLIB) $(LIBCHECK_LIBS)
+
+test_ebgenv_api_internal_CFLAGS = $(AM_CFLAGS)
+test_ebgenv_api_internal_SOURCES = test_ebgenv_api_internal.c $(SRC_TEST_COMMON)
+test_ebgenv_api_internal_LDADD = $(FAT_TESTLIB) $(LIBCHECK_LIBS)
-check_PROGRAMS = test_api
+test_ebgenv_api_CFLAGS = $(AM_CFLAGS) -Wl,--wrap=bgenv_set -Wl,--wrap=bgenv_get
+test_ebgenv_api_SOURCES = test_ebgenv_api.c $(SRC_TEST_COMMON)
+test_ebgenv_api_LDADD = $(FAT_TESTLIB) $(LIBCHECK_LIBS)
TESTS = $(check_PROGRAMS)
diff --git a/tools/tests/fake_devices.c b/tools/tests/fake_devices.c
new file mode 100644
index 0000000..58a47bd
--- /dev/null
+++ b/tools/tests/fake_devices.c
@@ -0,0 +1,94 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (c) Siemens AG, 2017
+ *
+ * Authors:
+ * Andreas Reichel <
andreas.r...@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <stdlib.h>
+#include <env_api.h>
+#include <env_config_file.h>
+#include <env_config_partitions.h>
+#include <fake_devices.h>
+
+PedDevice *fake_devices;
+int num_fake_devices;
+
+void allocate_fake_devices(int n)
+{
+ fake_devices = (PedDevice *)malloc(n * sizeof(PedDevice));
+ for (char i = 0; i < n; i++) {
+ asprintf(&fake_devices[i].model, "%s", "Fake Device");
+ asprintf(&fake_devices[i].path, "/dev/nobrain_%c", 'a' + i);
+ fake_devices[i].part_list = NULL;
+ fake_devices[i].next = NULL;
+ }
+ num_fake_devices = n;
+ for (char i = n - 1; i > 0; i--) {
+ fake_devices[i-1].next = &fake_devices[i];
+ }
+}
+
+void add_fake_partition(int devnum)
+{
+ PedPartition **pp = &fake_devices[devnum].part_list;
+
+ int16_t num = 0;
+ while (*pp) {
+ pp = &(*pp)->next;
+ num++;
+ }
+ *pp = (PedPartition *)malloc(sizeof(PedPartition));
+ (*pp)->num = num;
+ (*pp)->fs_type = (PedFileSystemType *)malloc(sizeof(PedFileSystemType));
+ asprintf(&(*pp)->fs_type->name, "%s", "fat16");
+ (*pp)->next = NULL;
+}
+
+void remove_fake_partitions(int n)
+{
+ PedPartition *pp = fake_devices[n].part_list;
+ PedPartition *next;
+ while(pp) {
+ next = pp->next;
+ if (!pp->fs_type)
+ goto skip_fstype;
+ if (pp->fs_type->name)
+ free(pp->fs_type->name);
+ free(pp->fs_type);
+skip_fstype:
+ free(pp);
+ pp = next;
+ }
+}
+
+void free_fake_devices()
+{
+ if (!fake_devices) {
+ return;
+ }
+
+ for (int i = 0; i < num_fake_devices; i++) {
+ if (fake_devices[i].model)
+ free(fake_devices[i].model);
+ if (fake_devices[i].path)
+ free(fake_devices[i].path);
+ if (fake_devices[i].part_list)
+ remove_fake_partitions(i);
+ }
+
+ free(fake_devices);
+}
+
+PedDevice *ped_device_get_next_custom_fake(const PedDevice *dev)
+{
+ if (!dev)
+ return fake_devices;
+
+ return dev->next;
+}
diff --git a/tools/tests/fake_devices.h b/tools/tests/fake_devices.h
new file mode 100644
index 0000000..aa5f423
--- /dev/null
+++ b/tools/tests/fake_devices.h
@@ -0,0 +1,28 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (c) Siemens AG, 2017
+ *
+ * Authors:
+ * Andreas Reichel <
andreas.r...@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef __FAKE_DEVICES_H__
+#define __FAKE_DEVICES_H__
+
+#include <ebgpart.h>
+
+extern PedDevice *fake_devices;
+extern int num_fake_devices;
+
+void allocate_fake_devices(int n);
+void add_fake_partition(int devnum);
+void remove_fake_partitions(int n);
+void free_fake_devices(void);
+
+PedDevice *ped_device_get_next_custom_fake(const PedDevice *dev);
+
+#endif // __FAKE_DEVICES_H__
diff --git a/tools/tests/test_bgenv_init_retval.c b/tools/tests/test_bgenv_init_retval.c
new file mode 100644
index 0000000..76ec253
--- /dev/null
+++ b/tools/tests/test_bgenv_init_retval.c
@@ -0,0 +1,100 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (c) Siemens AG, 2017
+ *
+ * Authors:
+ * Andreas Reichel <
andreas.r...@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef ENV_NUM_CONFIG_PARTITIONS
+# define ENV_NUM_CONFIG_PARTITIONS 2
+#endif
+
+#include <stdlib.h>
+#include <check.h>
+#include <fff.h>
+#include <env_api.h>
+#include <env_config_file.h>
+#include <env_config_partitions.h>
+
+DEFINE_FFF_GLOBALS;
+
+static char *devpath = "/dev/nobrain";
+
+bool read_env(CONFIG_PART *part, BG_ENVDATA *env);
+
+Suite *env_api_fat_suite(void);
+bool probe_config_partitions_custom_fake(CONFIG_PART *cfgpart);
+bool read_env_custom_fake(CONFIG_PART *cp, BG_ENVDATA *env);
+
+Suite *ebg_test_suite(void);
+
+bool probe_config_partitions_custom_fake(CONFIG_PART *cfgpart)
+{
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ cfgpart[i].devpath = devpath;
+ }
+ return true;
+}
+
+bool read_env_custom_fake(CONFIG_PART *cp, BG_ENVDATA *env)
+{
+ if (!env) {
+ return false;
+ }
+ memset(env, 0, sizeof(BG_ENVDATA));
+ return true;
+}
+
+FAKE_VALUE_FUNC(bool, probe_config_partitions, CONFIG_PART *);
+FAKE_VALUE_FUNC(bool, read_env, CONFIG_PART *, BG_ENVDATA *);
+
+START_TEST(env_api_fat_test_bgenv_init_retval)
+{
+ bool result;
+ /* In this unit test, contents of environment data are
+ * faked to be all zero
+ */
+
+ /* Test if bgenv_init fails if no config partitions are found
+ */
+ RESET_FAKE(probe_config_partitions);
+
+ probe_config_partitions_fake.return_val = false;
+
+ result = bgenv_init();
+
+ ck_assert(probe_config_partitions_fake.call_count == 1);
+ ck_assert(result == false);
+
+ /* Test if bgenv_init succeeds if config partitions are found
+ */
+ RESET_FAKE(probe_config_partitions);
+
+ probe_config_partitions_fake.custom_fake = probe_config_partitions_custom_fake;
+ read_env_fake.custom_fake = read_env_custom_fake;
+ result = bgenv_init();
+
+ ck_assert(probe_config_partitions_fake.call_count == 1);
+ ck_assert(read_env_fake.call_count == ENV_NUM_CONFIG_PARTS);
+ ck_assert(result == true);
+}
+END_TEST
+
+Suite *ebg_test_suite(void)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create("env_api_fat");
+
+ tc_core = tcase_create("Core");
+ tcase_add_test(tc_core, env_api_fat_test_bgenv_init_retval);
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
diff --git a/tools/tests/test_ebgenv_api.c b/tools/tests/test_ebgenv_api.c
new file mode 100644
index 0000000..530f338
--- /dev/null
+++ b/tools/tests/test_ebgenv_api.c
@@ -0,0 +1,641 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (c) Siemens AG, 2017
+ *
+ * Authors:
+ * Andreas Reichel <
andreas.r...@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <config.h>
+
+#ifndef ENV_NUM_CONFIG_PARTITIONS
+# define ENV_NUM_CONFIG_PARTITIONS 2
+#endif
+
+#include <stdlib.h>
+#include <check.h>
+#include <fff.h>
+#include <env_api.h>
+#include <ebgenv.h>
+#include <env_config_file.h>
+#include <env_config_partitions.h>
+
+DEFINE_FFF_GLOBALS;
+
+static char *devpath = "/dev/nobrain";
+
+Suite *ebg_test_suite(void);
+
+extern bool write_env(CONFIG_PART *part, BG_ENVDATA *env);
+extern bool bgenv_write(BGENV *);
+extern bool bgenv_init(void);
+extern bool bgenv_close(BGENV *);
+extern BGENV *bgenv_create_new(void);
+
+FAKE_VALUE_FUNC(bool, bgenv_init);
+FAKE_VALUE_FUNC(bool, bgenv_write, BGENV *);
+FAKE_VALUE_FUNC(bool, bgenv_close, BGENV *);
+
+int __real_bgenv_set(BGENV *, char *, char *, void *, uint32_t);
+int __wrap_bgenv_set(BGENV *, char *, char *, void *, uint32_t);
+int __real_bgenv_get(BGENV *, char *, char *, void *, uint32_t);
+int __wrap_bgenv_get(BGENV *, char *, char *, void *, uint32_t);
+
+BGENV *bgenv_getset_arg0;
+char *bgenv_getset_arg1;
+char *bgenv_getset_arg2;
+void *bgenv_getset_arg3;
+uint32_t bgenv_getset_arg4;
+int bgenv_get_call_count;
+int bgenv_set_call_count;
+
+/* FFF does not provide calls to the original function, so in this case
+ * we need to use the linker wrapping method and reimplement some of FFFs
+ * functionality.
+ */
+int __wrap_bgenv_get(BGENV *env, char *key, char *type, void *buffer, uint32_t len)
+{
+ bgenv_get_call_count++;
+ bgenv_getset_arg0 = env;
+ bgenv_getset_arg1 = key;
+ bgenv_getset_arg2 = type;
+ bgenv_getset_arg3 = buffer;
+ bgenv_getset_arg4 = len;
+ return __real_bgenv_get(env, key, type, buffer, len);
+}
+
+int __wrap_bgenv_set(BGENV *env, char *key, char *type, void *buffer, uint32_t len)
+{
+ bgenv_set_call_count++;
+ bgenv_getset_arg0 = env;
+ bgenv_getset_arg1 = key;
+ bgenv_getset_arg2 = type;
+ bgenv_getset_arg3 = buffer;
+ bgenv_getset_arg4 = len;
+ return __real_bgenv_set(env, key, type, buffer, len);
+}
+
+/* These variables substitute weakened symbols in the ebgenv library code
+ * so that all environment functions use these as data sources
+ */
+CONFIG_PART config_parts[ENV_NUM_CONFIG_PARTS];
+BG_ENVDATA envdata[ENV_NUM_CONFIG_PARTS];
+
+START_TEST(ebgenv_api_ebg_env_create_new)
+{
+ ebgenv_t e;
+ int ret;
+ wchar_t bufferw[10];
+ char buffer[10];
+ char *kernelfile = "kernel123";
+ char *kernelparams = "param456";
+
+ memset(&e, 0, sizeof(e));
+
+ /* Test if ebg_env_create_new returns EIO if bgenv_init
+ * returns false
+ */
+ bgenv_init_fake.return_val = false;
+ ret = ebg_env_create_new(&e);
+ ck_assert_int_eq(ret, EIO);
+
+ /* Test if errno is returned by ebg_env_created, if the bgenv pointer
+ * is NULL but ebg_new_env_created is true, which is contradictory.
+ * Also, ebg_new_env_created must be reset to false.
+ */
+ bgenv_init_fake.return_val = true;
+ bgenv_close_fake.return_val = true;
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++)
+ {
+ envdata[i].revision = i;
+ }
+ e.ebg_new_env_created = true;
+ e.bgenv = NULL;
+ errno = 3044;
+
+ ret = ebg_env_create_new(&e);
+
+ ck_assert_int_eq(ret, 3044);
+ ck_assert(e.ebg_new_env_created == false);
+
+ /* Check if values of the latest environment are copied if a new
+ * environment is created. The new environment must overwrite the
+ * oldest environment and revision and ustate must be set correctly.
+ */
+ envdata[ENV_NUM_CONFIG_PARTS-1].watchdog_timeout_sec = 44;
+ (void)str8to16(bufferw, kernelfile);
+ memcpy(envdata[ENV_NUM_CONFIG_PARTS-1].kernelfile, bufferw,
+ strlen(kernelfile) * 2 + 2);
+ (void)str8to16(bufferw, kernelparams);
+ memcpy(envdata[ENV_NUM_CONFIG_PARTS-1].kernelparams, bufferw,
+ strlen(kernelparams) * 2 + 2);
+ errno = 0;
+
+ ret = ebg_env_create_new(&e);
+
+ ck_assert_int_eq(errno, 0);
+ ck_assert_int_eq(ret, 0);
+ ck_assert(((BGENV *)e.bgenv)->data == &envdata[0]);
+ ck_assert_int_eq(
+ ((BGENV *)e.bgenv)->data->revision, ENV_NUM_CONFIG_PARTS);
+ ck_assert_int_eq(((BGENV *)e.bgenv)->data->ustate, USTATE_INSTALLED);
+ ck_assert_int_eq(((BGENV *)e.bgenv)->data->watchdog_timeout_sec, 44);
+ (void)str16to8(buffer, ((BGENV *)e.bgenv)->data->kernelfile);
+ ck_assert_int_eq(
+ strncmp(buffer, kernelfile, strlen(kernelfile) + 1), 0);
+ (void)str16to8(buffer, ((BGENV *)e.bgenv)->data->kernelparams);
+ ck_assert_int_eq(
+ strncmp(buffer, kernelparams, strlen(kernelparams) + 1), 0);
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_open_current)
+{
+ ebgenv_t e;
+ int ret;
+ memset(&e, 0, sizeof(e));
+
+ /* Test if ebg_env_open_current returns EIO if bgenv_init returns false
+ */
+ bgenv_init_fake.return_val = false;
+ ret = ebg_env_open_current(&e);
+
+ ck_assert_int_eq(ret, EIO);
+
+#if ENV_NUM_CONFIG_PARTS > 1
+
+ /* Test if ebg_env_open_current opens the environment with the highest
+ * revision
+ */
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ envdata[i].revision = i + 1;
+ }
+
+ bgenv_init_fake.return_val = true;
+ ret = ebg_env_open_current(&e);
+
+ ck_assert_int_eq(ret, 0);
+ ck_assert(((BGENV *)e.bgenv)->data == &envdata[ENV_NUM_CONFIG_PARTS-1]);
+
+ (void)ebg_env_close(&e);
+
+ envdata[0].revision = 0xFFFF;
+
+ ret = ebg_env_open_current(&e);
+
+ ck_assert_int_eq(ret, 0);
+ ck_assert(((BGENV *)e.bgenv)->data == &envdata[0]);
+
+ (void)ebg_env_close(&e);
+#endif
+
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_get)
+{
+ ebgenv_t e;
+ memset(&e, 0, sizeof(e));
+ int ret;
+ char buffer[1];
+
+ /* Test if ebg_env_get calls bg_env_get correctly and that it returns
+ * -EINVAL if no key is provided
+ */
+ bgenv_get_call_count = 0;
+
+ ret = ebg_env_get(&e, NULL, NULL);
+ ck_assert_int_eq(ret, -EINVAL);
+
+ ck_assert(bgenv_get_call_count == 1);
+ ck_assert(bgenv_getset_arg0 == e.bgenv);
+ ck_assert(bgenv_getset_arg1 == NULL);
+ ck_assert(bgenv_getset_arg2 == NULL);
+
+ /* Test if ebg_env_get retrieves correct data if given a valid
+ * environment handle.
+ */
+ e.bgenv = (BGENV *)calloc(1, sizeof(BGENV));
+ ck_assert(e.bgenv != NULL);
+
+ ((BGENV *)e.bgenv)->data = (BG_ENVDATA *)calloc(1, sizeof(BG_ENVDATA));
+ ck_assert(((BGENV *)e.bgenv)->data != NULL);
+
+ bgenv_get_call_count = 0;
+
+ (void)ebg_env_get(&e, "kernelfile", buffer);
+
+ ck_assert(bgenv_get_call_count == 1);
+ ck_assert(bgenv_getset_arg0 == e.bgenv);
+ ck_assert_int_eq(strcmp(bgenv_getset_arg1, "kernelfile"), 0);
+ ck_assert(bgenv_getset_arg3 == buffer);
+
+ free(((BGENV *)e.bgenv)->data);
+ free(e.bgenv);
+
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_set)
+{
+ ebgenv_t e;
+ memset(&e, 0, sizeof(e));
+ char *value = "dummy";
+
+ /* Check if ebg_env_set correctly calls bgenv_set
+ */
+ bgenv_set_call_count = 0;
+
+ e.bgenv = (BGENV *)calloc(1, sizeof(BGENV));
+ ck_assert(e.bgenv != NULL);
+
+ ((BGENV *)e.bgenv)->data = (BG_ENVDATA *)calloc(1, sizeof(BG_ENVDATA));
+ ck_assert(((BGENV *)e.bgenv)->data != NULL);
+
+ (void)ebg_env_set(&e, "kernelfile", value);
+
+ ck_assert(bgenv_set_call_count == 1);
+ ck_assert(bgenv_getset_arg0 == e.bgenv);
+ ck_assert_int_eq(strcmp(bgenv_getset_arg1, "kernelfile"), 0);
+ ck_assert(bgenv_getset_arg3 == value);
+ ck_assert(bgenv_getset_arg4 == strlen(value) + 1);
+
+ free(((BGENV *)e.bgenv)->data);
+ free(e.bgenv);
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_set_ex)
+{
+
+ ebgenv_t e;
+ memset(&e, 0, sizeof(e));
+ char *key = "mykey";
+ char *value = "dummy";
+ char *usertype = "mytype";
+ int32_t datalen = 5;
+
+ /* Check if ebg_env_set_ex correctly calls bgenv_set
+ */
+ bgenv_set_call_count = 0;
+
+ e.bgenv = (BGENV *)calloc(1, sizeof(BGENV));
+ ck_assert(e.bgenv != NULL);
+
+ ((BGENV *)e.bgenv)->data = (BG_ENVDATA *)calloc(1, sizeof(BG_ENVDATA));
+ ck_assert(((BGENV *)e.bgenv)->data != NULL);
+
+ bgenv_set_call_count = 0;
+
+ (void)ebg_env_set_ex(&e, key, usertype, (uint8_t *)value, datalen);
+
+ ck_assert(bgenv_set_call_count == 1);
+ ck_assert(bgenv_getset_arg0 == e.bgenv);
+ ck_assert_int_eq(strcmp(bgenv_getset_arg1, key), 0);
+ ck_assert_int_eq(strcmp(bgenv_getset_arg2, usertype), 0);
+ ck_assert(bgenv_getset_arg3 == value);
+ ck_assert(bgenv_getset_arg4 == datalen);
+
+ free(((BGENV *)e.bgenv)->data);
+ free(e.bgenv);
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_get_ex)
+{
+ ebgenv_t e;
+ memset(&e, 0, sizeof(e));
+ char *key = "mykey";
+ char buffer[5];
+ char type[7];
+ int32_t datalen = 5;
+
+ /* Check if ebg_env_get_ex correctly calls bgenv_get
+ */
+ bgenv_get_call_count = 0;
+
+ e.bgenv = (BGENV *)calloc(1, sizeof(BGENV));
+ ck_assert(e.bgenv != NULL);
+
+ ((BGENV *)e.bgenv)->data = (BG_ENVDATA *)calloc(1, sizeof(BG_ENVDATA));
+ ck_assert(((BGENV *)e.bgenv)->data != NULL);
+
+ bgenv_get_call_count = 0;
+
+ (void)ebg_env_get_ex(&e, key, type, (uint8_t *)buffer, datalen);
+
+ ck_assert(bgenv_get_call_count == 1);
+ ck_assert(bgenv_getset_arg0 == e.bgenv);
+ ck_assert_int_eq(strcmp(bgenv_getset_arg1, key), 0);
+ ck_assert(bgenv_getset_arg2 == type);
+ ck_assert(bgenv_getset_arg3 == buffer);
+ ck_assert(bgenv_getset_arg4 == datalen);
+
+ free(((BGENV *)e.bgenv)->data);
+ free(e.bgenv);
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_user_free)
+{
+ ebgenv_t e;
+ uint32_t ret;
+ memset(&e, 0, sizeof(e));
+
+ /* Check if ebg_env_user_free returns 0 if no environment handle
+ * is available (invalid context).
+ */
+ ret = ebg_env_user_free(&e);
+ ck_assert_int_eq(ret, 0);
+
+ /* Check if ebg_env_user_free returns 0 if no environment data
+ * is available (NULL environment).
+ */
+ e.bgenv = (BGENV *)calloc(1, sizeof(BGENV));
+ ck_assert(e.bgenv != NULL);
+
+ ret = ebg_env_user_free(&e);
+ ck_assert_int_eq(ret, 0);
+
+ /* Check if ebg_env_user_free returns ENV_MEM_USERVARS if environment
+ * user space is empty
+ */
+ ((BGENV *)e.bgenv)->data = (BG_ENVDATA *)calloc(1, sizeof(BG_ENVDATA));
+ ck_assert(((BGENV *)e.bgenv)->data != NULL);
+
+ ret = ebg_env_user_free(&e);
+ ck_assert_int_eq(ret, ENV_MEM_USERVARS);
+
+ free(((BGENV *)e.bgenv)->data);
+ free(e.bgenv);
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_getglobalstate)
+{
+#if ENV_NUM_CONFIG_PARTS > 1
+ ebgenv_t e;
+ uint16_t state;
+ memset(&e, 0, sizeof(e));
+
+ /* Test if ebg_env_getglobalstate returns OK if current environment
+ * is set to OK
+ */
+ e.bgenv = (BGENV *)calloc(1, sizeof(BGENV));
+ ck_assert(e.bgenv != NULL);
+
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ envdata[i].revision = i + 1;
+ }
+
+ envdata[1].revision = 0;
+ envdata[1].ustate = USTATE_OK;
+
+ state = ebg_env_getglobalstate(&e);
+ ck_assert_int_eq(state, USTATE_OK);
+
+ /* Test if ebg_env_getglobalstate returns FAILED if current environment
+ * is set to FAILED with revision 0
+ */
+ envdata[1].revision = 0;
+ envdata[1].ustate = USTATE_FAILED;
+
+ state = ebg_env_getglobalstate(&e);
+ ck_assert_int_eq(state, USTATE_FAILED);
+
+ /* Test if ebg_env_getglobalstate returns FAILED if current environment
+ * is set to FAILED with non-zero revision
+ */
+ envdata[1].revision = 15;
+
+ state = ebg_env_getglobalstate(&e);
+ ck_assert_int_eq(state, USTATE_FAILED);
+
+ /* Test if ebg_env_getglobalstate returns INSTALLED if current
+ * environment is set to INSTALLED
+ */
+ envdata[1].revision = 15;
+ envdata[1].ustate = USTATE_INSTALLED;
+
+ state = ebg_env_getglobalstate(&e);
+ ck_assert_int_eq(state, USTATE_INSTALLED);
+
+ /* Test if ebg_env_getglobalstate returns FAILED if current environment
+ * is set to OK and any other is set to FAILED
+ */
+ envdata[1].ustate = USTATE_OK;
+ envdata[0].revision = 0;
+ envdata[0].ustate = USTATE_FAILED;
+
+ state = ebg_env_getglobalstate(&e);
+ ck_assert_int_eq(state, USTATE_FAILED);
+
+ /* Test if ebg_env_getglobalstate returns OK if current environment is
+ * set to OK and any other is set to INSTALLED
+ */
+ envdata[0].ustate = USTATE_INSTALLED;
+
+ state = ebg_env_getglobalstate(&e);
+ ck_assert_int_eq(state, USTATE_OK);
+
+ /* Test if ebg_env_getglobalstate returns TESTING if current
+ * environment is set to TESTING and none is FAILED
+ */
+ envdata[0].ustate = USTATE_OK;
+ envdata[1].ustate = USTATE_TESTING;
+
+ state = ebg_env_getglobalstate(&e);
+ ck_assert_int_eq(state, USTATE_TESTING);
+
+ /* Test if ebg_env_getglobalstate returns OK if current environment is
+ * set to OK and none is TESTING
+ */
+ envdata[0].ustate = USTATE_TESTING;
+ envdata[1].ustate = USTATE_OK;
+
+ state = ebg_env_getglobalstate(&e);
+ ck_assert_int_eq(state, USTATE_OK);
+
+ free(e.bgenv);
+#endif
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_setglobalstate)
+{
+#if ENV_NUM_CONFIG_PARTS > 1
+ ebgenv_t e;
+ int ret;
+ memset(&e, 0, sizeof(e));
+
+ /* Test if ebg_env_setglobalstate sets only current to FAILED
+ */
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ envdata[i].revision = i + 1;
+ }
+
+ bgenv_init_fake.return_val = true;
+
+ ret = ebg_env_open_current(&e);
+
+ ck_assert_int_eq(ret, 0);
+ ck_assert(((BGENV *)e.bgenv)->data == &envdata[ENV_NUM_CONFIG_PARTS-1]);
+
+ envdata[0].ustate = USTATE_OK;
+ envdata[1].ustate = USTATE_OK;
+
+ ret = ebg_env_setglobalstate(&e, 0xFFF);
+ ck_assert_int_eq(ret, EINVAL);
+
+ ret = ebg_env_setglobalstate(&e, USTATE_FAILED);
+
+ ck_assert_int_eq(ret, 0);
+
+ ck_assert_int_eq(envdata[0].ustate, USTATE_OK);
+ ck_assert_int_eq(envdata[ENV_NUM_CONFIG_PARTS-1].ustate, USTATE_FAILED);
+
+ envdata[1].ustate = USTATE_OK;
+ envdata[0].ustate = USTATE_OK;
+
+ (void)ebg_env_close(&e);
+
+ envdata[0].revision = 1313;
+
+ ret = ebg_env_open_current(&e);
+ ck_assert_int_eq(ret, 0);
+
+ ret = ebg_env_setglobalstate(&e, USTATE_FAILED);
+ ck_assert_int_eq(ret, 0);
+ ck_assert_int_eq(envdata[0].ustate, USTATE_FAILED);
+ ck_assert_int_eq(envdata[1].ustate, USTATE_OK);
+
+ /* Test if ebg_env_setglobalstate sets ALL environments to OK
+ */
+ envdata[0].ustate = USTATE_FAILED;
+ envdata[1].ustate = USTATE_FAILED;
+
+ bgenv_write_fake.return_val = true;
+ bgenv_close_fake.return_val = true;
+
+ ret = ebg_env_setglobalstate(&e, USTATE_OK);
+
+ ck_assert_int_eq(ret, 0);
+ ck_assert_int_eq(envdata[0].ustate, USTATE_OK);
+ ck_assert_int_eq(envdata[1].ustate, USTATE_OK);
+
+ /* Test if ebg_env_setglobalstate sets current environment to TESTING
+ */
+ envdata[0].ustate = USTATE_INSTALLED;
+ envdata[1].ustate = USTATE_INSTALLED;
+
+ ret = ebg_env_setglobalstate(&e, USTATE_TESTING);
+
+ ck_assert_int_eq(ret, 0);
+ ck_assert_int_eq(envdata[0].ustate, USTATE_TESTING);
+ ck_assert_int_eq(envdata[1].ustate, USTATE_INSTALLED);
+
+ /* Test if ebg_env_setglobalstate fails and returns EIO if bgenv_write
+ * fails
+ */
+ bgenv_write_fake.return_val = false;
+ bgenv_close_fake.return_val = true;
+
+ ret = ebg_env_setglobalstate(&e, USTATE_OK);
+
+ ck_assert_int_eq(ret, EIO);
+
+ /* Test if ebg_env_setglobalstate fails and returns EIO if bgenv_close
+ * fails
+ */
+ bgenv_write_fake.return_val = true;
+ bgenv_close_fake.return_val = false;
+
+ ret = ebg_env_setglobalstate(&e, USTATE_OK);
+
+ ck_assert_int_eq(ret, EIO);
+
+ (void)ebg_env_close(&e);
+#endif
+}
+END_TEST
+
+START_TEST(ebgenv_api_ebg_env_close)
+{
+ ebgenv_t e;
+ int ret;
+ memset(&e, 0, sizeof(e));
+
+ /* Test if ebg_env_close fails with invalid context and returns EIO
+ */
+ ret = ebg_env_close(&e);
+ ck_assert_int_eq(ret, EIO);
+
+ /* Test if ebg_env_close fails and returns EIO if bgenv_write fails
+ */
+ e.bgenv = calloc(1, sizeof(BGENV));
+ ck_assert(e.bgenv != NULL);
+
+ ((BGENV *)e.bgenv)->data = calloc(1, sizeof(BG_ENVDATA));
+ bgenv_write_fake.return_val = false;
+ bgenv_close_fake.return_val = true;
+ ret = ebg_env_close(&e);
+
+ ck_assert_int_eq(ret, EIO);
+
+ /* Test if ebg_env_close fails and returns EIO if bgenv_close fails.
+ */
+ bgenv_write_fake.return_val = true;
+ bgenv_close_fake.return_val = false;
+ ret = ebg_env_close(&e);
+
+ ck_assert_int_eq(ret, EIO);
+
+ /* Test if ebg_env_close is successful if all prerequisites are met
+ */
+ bgenv_write_fake.return_val = true;
+ bgenv_close_fake.return_val = true;
+ BGENV *save_ptr = e.bgenv;
+ ret = ebg_env_close(&e);
+
+ ck_assert_int_eq(ret, 0);
+ ck_assert(e.bgenv == NULL);
+
+ free(save_ptr->data);
+ free(save_ptr);
+}
+END_TEST
+
+Suite *ebg_test_suite(void)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create("ebgenv_api");
+
+ TFun tfuncs[] = {
+ ebgenv_api_ebg_env_create_new,
+ ebgenv_api_ebg_env_open_current,
+ ebgenv_api_ebg_env_get,
+ ebgenv_api_ebg_env_set,
+ ebgenv_api_ebg_env_set_ex,
+ ebgenv_api_ebg_env_get_ex,
+ ebgenv_api_ebg_env_user_free,
+ ebgenv_api_ebg_env_getglobalstate,
+ ebgenv_api_ebg_env_setglobalstate,
+ ebgenv_api_ebg_env_close
+ };
+
+ tc_core = tcase_create("Core");
+
+ for (int i = 0; i < sizeof(tfuncs)/sizeof(void *); i++) {
+ tcase_add_test(tc_core, tfuncs[i]);
+ }
+
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
diff --git a/tools/tests/test_ebgenv_api_internal.c b/tools/tests/test_ebgenv_api_internal.c
new file mode 100644
index 0000000..1f5ce93
--- /dev/null
+++ b/tools/tests/test_ebgenv_api_internal.c
@@ -0,0 +1,416 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (c) Siemens AG, 2017
+ *
+ * Authors:
+ * Andreas Reichel <
andreas.r...@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef ENV_NUM_CONFIG_PARTITIONS
+# define ENV_NUM_CONFIG_PARTITIONS 2
+#endif
+
+#include <stdlib.h>
+#include <check.h>
+#include <fff.h>
+#include <env_api.h>
+#include <env_config_file.h>
+#include <env_config_partitions.h>
+
+DEFINE_FFF_GLOBALS;
+
+static char *devpath = "/dev/nobrain";
+
+Suite *ebg_test_suite(void);
+
+extern bool write_env(CONFIG_PART *part, BG_ENVDATA *env);
+extern EBGENVKEY bgenv_str2enum(char *);
+extern BGENV *bgenv_open_by_index(uint32_t index);
+
+bool write_env_custom_fake(CONFIG_PART *part, BG_ENVDATA *env);
+
+bool write_env_custom_fake(CONFIG_PART *part, BG_ENVDATA *env)
+{
+ return true;
+}
+
+FAKE_VALUE_FUNC(bool, write_env, CONFIG_PART *, BG_ENVDATA *);
+
+CONFIG_PART config_parts[ENV_NUM_CONFIG_PARTS];
+BG_ENVDATA envdata[ENV_NUM_CONFIG_PARTS];
+
+START_TEST(ebgenv_api_internal_strXtoY)
+{
+ wchar_t *exp_res = L"This is a test";
+ wchar_t bufferw[16];
+ char buffer[16];
+ char *input = "This is a test";
+ wchar_t *resw;
+ char *res;
+
+ /* Test conversion from ASCII bits to 16 bit encoding
+ */
+ resw = str8to16(bufferw, input);
+
+ /* cannot use glibc for 16-bit wchar_t
+ * string compare since glibc has 32-bit wchar_t
+ */
+ for (int i = 0; i < strlen(input); i++) {
+ ck_assert(resw[i] == exp_res[i]);
+ }
+
+ /* Test conversion from 16 bit encoding to ASCII
+ */
+ res = str16to8(buffer, exp_res);
+
+ ck_assert(strcmp(res, input) == 0);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_str2enum)
+{
+ EBGENVKEY e;
+
+ /* Test bgenv_str2enum for correct key conversion
+ */
+ e = bgenv_str2enum("kernelfile");
+ ck_assert(e == EBGENV_KERNELFILE);
+
+ e = bgenv_str2enum("kernelparams");
+ ck_assert(e == EBGENV_KERNELPARAMS);
+
+ e = bgenv_str2enum("watchdog_timeout_sec");
+ ck_assert(e == EBGENV_WATCHDOG_TIMEOUT_SEC);
+
+ e = bgenv_str2enum("revision");
+ ck_assert(e == EBGENV_REVISION);
+
+ e = bgenv_str2enum("ustate");
+ ck_assert(e == EBGENV_USTATE);
+
+ /* Test if bgenv_str2enum returns EBGENV_UNKNOWN for empty and invalid
+ * keys
+ */
+ e = bgenv_str2enum("XZXOOZOOZIOFZOFZ");
+ ck_assert(e == EBGENV_UNKNOWN);
+
+ e = bgenv_str2enum("");
+ ck_assert(e == EBGENV_UNKNOWN);
+
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_open_by_index)
+{
+ BGENV *handle;
+
+ handle = bgenv_open_by_index(0);
+ ck_assert(handle != NULL);
+ ck_assert(handle->desc == &config_parts[0]);
+ ck_assert(handle->data == &envdata[0]);
+ free(handle);
+
+ handle = bgenv_open_by_index(ENV_NUM_CONFIG_PARTS-1);
+ ck_assert(handle != NULL);
+ ck_assert(handle->desc == &config_parts[ENV_NUM_CONFIG_PARTS-1]);
+ ck_assert(handle->data == &envdata[ENV_NUM_CONFIG_PARTS-1]);
+ free(handle);
+
+ /* Test if bgenv_open_by_index returns NULL if parameter is out of
+ * range
+ */
+ handle = bgenv_open_by_index(ENV_NUM_CONFIG_PARTS);
+ ck_assert(handle == NULL);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_open_oldest)
+{
+ BGENV *handle;
+
+ /* Test if bgenv_open_oldest returns a handle for the environment with
+ * the lowest revision
+ */
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++)
+ {
+ envdata[i].revision = ENV_NUM_CONFIG_PARTS - i;
+ }
+ handle = bgenv_open_oldest();
+ ck_assert(handle != NULL);
+ ck_assert(handle->desc == &config_parts[ENV_NUM_CONFIG_PARTS-1]);
+ ck_assert(handle->data == &envdata[ENV_NUM_CONFIG_PARTS-1]);
+ free(handle);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_open_latest)
+{
+ BGENV *handle;
+
+ /* Test if bgenv_open_latest returns a handle for the environment with
+ * the highest revision
+ */
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++)
+ {
+ envdata[i].revision = ENV_NUM_CONFIG_PARTS - i;
+ }
+ handle = bgenv_open_latest();
+ ck_assert(handle != NULL);
+ ck_assert(handle->desc == &config_parts[0]);
+ ck_assert(handle->data == &envdata[0]);
+ free(handle);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_write)
+{
+ bool res;
+ BGENV *dummy_env;
+
+ dummy_env = calloc(1, sizeof(BGENV));
+ if (!dummy_env)
+ goto bgew_error;
+
+ RESET_FAKE(write_env);
+ write_env_fake.custom_fake = write_env_custom_fake;
+
+ /* Test if writing with a NULL-handle fails
+ */
+ res = bgenv_write(NULL);
+ ck_assert(write_env_fake.call_count == 0);
+ ck_assert(res == false);
+
+ /* Test if writing with a handle describing no partition
+ * and no environment data fails
+ */
+ res = bgenv_write(dummy_env);
+ ck_assert(write_env_fake.call_count == 0);
+ ck_assert(res == false);
+
+ /* Test if writing with a handle describing both partition
+ * and envrionment data succeeds
+ */
+ dummy_env->desc = calloc(1, sizeof(CONFIG_PART));
+ if (!dummy_env->desc)
+ goto bgew_error;
+
+ dummy_env->data = calloc(1, sizeof(BG_ENVDATA));
+ if (!dummy_env->data)
+ goto bgew_error;
+
+ res = bgenv_write(dummy_env);
+ ck_assert(write_env_fake.call_count == 1);
+ ck_assert(res == true);
+
+ return;
+
+bgew_error:
+ free(dummy_env->data);
+ free(dummy_env->desc);
+ free(dummy_env);
+ exit(errno);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_read)
+{
+ BGENV env;
+ BG_ENVDATA data;
+
+ env.data = &data;
+
+ /* Test if bgenv_read returns a pointer to the environment data
+ */
+ BG_ENVDATA *res = bgenv_read(&env);
+ ck_assert(res == env.data);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_create_new)
+{
+ BGENV *handle;
+ int max = ENV_NUM_CONFIG_PARTS;
+
+ for (int i = 0; i < max; i++)
+ {
+ envdata[i].revision = max - i;
+ }
+
+ /* Test if bgenv_create_new updates the oldest environment with default
+ * values and sets its revision to revision(latest)+1
+ */
+ handle = bgenv_create_new();
+
+ ck_assert(handle != NULL);
+ ck_assert(handle->data == &envdata[max-1]);
+ ck_assert(envdata[max-1].revision == max+1);
+ ck_assert(envdata[max-1].watchdog_timeout_sec == 30);
+
+ free(handle);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_get)
+{
+ BGENV *handle = bgenv_open_latest();
+ ck_assert(handle != NULL);
+
+ wchar_t buffer[ENV_STRING_LENGTH];
+ char *test_strings[] = {
+ "kernelfile_test123",
+ "kernelparams_test123",
+ };
+ void *dests[] = {
+ &handle->data->kernelfile,
+ &handle->data->kernelparams,
+ };
+
+ for (int i = 0; i < sizeof(test_strings)/sizeof(void*); i++)
+ {
+ memcpy(dests[i], str8to16(buffer, test_strings[i]),
+ strlen(test_strings[i]) * 2 + 2);
+ }
+ handle->data->watchdog_timeout_sec = 44;
+ handle->data->revision = 10000;
+ handle->data->ustate = USTATE_INSTALLED;
+
+ char *type = NULL, *data = NULL;
+ char buffera[22];
+ int res;
+
+ /* Test if bgenv_get fails if maxlen is set to 0
+ */
+ res = bgenv_get(handle, "kernelfile", type, data, 0);
+ ck_assert_int_eq(res, -EINVAL);
+
+ /* Test if bgenv_get fails if key is NULL
+ */
+ res = bgenv_get(handle, NULL, type, data, 1000);
+ ck_assert_int_eq(res, -EINVAL);
+
+ /* Test if bgenv_get fails if no environment is provided
+ */
+ res = bgenv_get(NULL, "kernelfile", type, NULL, 1000);
+ ck_assert_int_eq(res, -EPERM);
+
+ /* Test if bgenv_get returns the correct size of the needed
+ * buffer if provided with a NULL buffer
+ */
+ res = bgenv_get(handle, "kernelfile", type, NULL, 1000);
+ ck_assert_int_eq(res, strlen(test_strings[0]) + 1);
+
+ /* Test if bgenv_get returns the correct value
+ */
+ res = bgenv_get(handle, "kernelfile", type, buffera, res);
+ ck_assert_int_eq(strcmp(buffera, test_strings[0]), 0);
+
+ res = bgenv_get(handle, "kernelparams", type, NULL, 1000);
+ res = bgenv_get(handle, "kernelparams", type, buffera, res);
+ ck_assert_int_eq(strcmp(buffera, test_strings[1]), 0);
+
+ free(handle);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_bgenv_set)
+{
+ int res;
+
+ BGENV *handle = bgenv_open_latest();
+ ck_assert(handle != NULL);
+ ck_assert(handle->data != NULL);
+
+ /* Test if bgenv_set returns -EINVAL if the handle is invalid
+ */
+ res = bgenv_set(NULL, "kernelfile", NULL, NULL, 0);
+ ck_assert_int_eq(res, -EINVAL);
+
+ /* Test if bgenv_set returns -EINVAL if the key is invalid
+ */
+ res = bgenv_set(handle, "AOFIJAOEGIHA", NULL, NULL, 0);
+ ck_assert_int_eq(res, -EINVAL);
+
+ /* Test if bgenv_set works correctly for valid parameters
+ */
+ res = bgenv_set(handle, "kernelfile", NULL, "vmlinuz", 8);
+ ck_assert_int_eq(res, 0);
+
+ char buffer[8];
+ char *kfile = str16to8(buffer, handle->data->kernelfile);
+
+ ck_assert(strcmp(kfile, "vmlinuz") == 0);
+
+ res = bgenv_set(handle, "watchdog_timeout_sec", NULL, "-0", 2);
+ ck_assert_int_eq(res, 0);
+ ck_assert_int_eq(handle->data->watchdog_timeout_sec, 0);
+
+ res = bgenv_set(handle, "watchdog_timeout_sec", NULL, "311", 4);
+ ck_assert_int_eq(res, 0);
+ ck_assert_int_eq(handle->data->watchdog_timeout_sec, 311);
+
+ res = bgenv_set(handle, "kernelparams", NULL, "root=", 6);
+ ck_assert_int_eq(res, 0);
+
+ char *kparm = str16to8(buffer, handle->data->kernelparams);
+
+ ck_assert(strcmp(kparm, "root=") == 0);
+
+ res = bgenv_set(handle, "ustate", NULL, "2", 2);
+ ck_assert_int_eq(res, 0);
+
+ ck_assert_int_eq(handle->data->ustate, 2);
+
+ res = bgenv_set(handle, "revision", NULL, "0", 2);
+ ck_assert_int_eq(res, 0);
+ ck_assert_int_eq(handle->data->revision, 0);
+
+ res = bgenv_set(handle, "revision", NULL, "10301", 6);
+ ck_assert_int_eq(res, 0);
+ ck_assert_int_eq(handle->data->revision, 10301);
+
+ free(handle);
+}
+END_TEST
+
+START_TEST(ebgenv_api_internal_uservars)
+{
+
+
+}
+END_TEST
+
+Suite *ebg_test_suite(void)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create("ebgenv_api");
+
+ TFun tfuncs[] = {
+ ebgenv_api_internal_strXtoY,
+ ebgenv_api_internal_bgenv_str2enum,
+ ebgenv_api_internal_bgenv_open_by_index,
+ ebgenv_api_internal_bgenv_open_oldest,
+ ebgenv_api_internal_bgenv_open_latest,
+ ebgenv_api_internal_bgenv_write,
+ ebgenv_api_internal_bgenv_read,
+ ebgenv_api_internal_bgenv_create_new,
+ ebgenv_api_internal_bgenv_get,
+ ebgenv_api_internal_bgenv_set,
+ ebgenv_api_internal_uservars
+ };
+
+ tc_core = tcase_create("Core");
+
+ for (int i = 0; i < sizeof(tfuncs)/sizeof(void *); i++) {
+ tcase_add_test(tc_core, tfuncs[i]);
+ }
+
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
diff --git a/tools/tests/test_main.c b/tools/tests/test_main.c
new file mode 100644
index 0000000..a25e092
--- /dev/null
+++ b/tools/tests/test_main.c
@@ -0,0 +1,34 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (c) Siemens AG, 2017
+ *
+ * Authors:
+ * Andreas Reichel <
andreas.r...@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <stdlib.h>
+#include <check.h>
+#include <fff.h>
+
+extern Suite *ebg_test_suite(void);
+
+int main(void)
+{
+ int number_failed;
+
+ Suite *s;
+ SRunner *sr;
+
+ s = ebg_test_suite();
+ sr = srunner_create(s);
+
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tools/tests/test_probe_config_file.c b/tools/tests/test_probe_config_file.c
new file mode 100644
index 0000000..edc8f6a
--- /dev/null
+++ b/tools/tests/test_probe_config_file.c
@@ -0,0 +1,202 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (c) Siemens AG, 2017
+ *
+ * Authors:
+ * Andreas Reichel <
andreas.r...@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef ENV_NUM_CONFIG_PARTITIONS
+# define ENV_NUM_CONFIG_PARTITIONS 2
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/queue.h>
+#include <check.h>
+#include <fff.h>
+#include <env_api.h>
+#include <env_config_file.h>
+#include <env_config_partitions.h>
+#include <ebgpart.h>
+#include <stdio.h>
+#include <env_disk_utils.h>
+#include <fake_devices.h>
+
+DEFINE_FFF_GLOBALS;
+
+Suite *ebg_test_suite(void);
+
+char *get_mountpoint_custom_fake(char *devpath);
+void delete_temp_files(void);
+
+bool __wrap_probe_config_file(CONFIG_PART *);
+bool __real_probe_config_file(CONFIG_PART *);
+int probe_config_file_call_count;
+
+char *fake_mountpoint = "/tmp/tmp.XXXXXX";
+
+struct stailhead *headp;
+struct fake_env_file_path {
+ char *path;
+ STAILQ_ENTRY(fake_env_file_path) fake_env_file_paths;
+};
+STAILQ_HEAD(stailhead, fake_env_file_path) head = STAILQ_HEAD_INITIALIZER(head);
+
+char *get_mountpoint_custom_fake(char *devpath)
+{
+ char *buff = NULL;
+ char *tmpdir = NULL;
+ char *tmpfile = NULL;
+
+ if (asprintf(&tmpdir, "%s", fake_mountpoint) == -1)
+ {
+ tmpdir = NULL;
+ goto fake_mountpoint_error;
+ }
+
+ tmpdir = mkdtemp(tmpdir);
+ if (!tmpdir)
+ goto fake_mountpoint_error;
+
+ if (asprintf(&buff, "%s", tmpdir) == -1) {
+ buff = NULL;
+ goto fake_mountpoint_error;
+ }
+
+ if (asprintf(&tmpfile, "%s/%s", tmpdir, FAT_ENV_FILENAME) == -1) {
+ tmpfile = NULL;
+ goto fake_mountpoint_error;
+ }
+
+ /* create a fake environment file
+ */
+ FILE *temp_env_file = fopen(tmpfile, "w");
+
+ BG_ENVDATA env_data;
+ memset(&env_data, 0, sizeof(BG_ENVDATA));
+ fwrite(&env_data, sizeof(BG_ENVDATA), 1, temp_env_file);
+ fclose(temp_env_file);
+
+ free(tmpfile);
+ free(tmpdir);
+
+ struct fake_env_file_path *fefp;
+ fefp = malloc(sizeof(struct fake_env_file_path));
+
+ /* If possibly store created temporary files and paths in a list to
+ * tidy up later. If not, the test should not fail because of this.
+ */
+ char *buffer_copy;
+ asprintf(&buffer_copy, "%s", buff);
+
+ if (fefp && buffer_copy) {
+ fefp->path = buffer_copy;
+ STAILQ_INSERT_TAIL(&head, fefp, fake_env_file_paths);
+ }
+ return buff;
+
+fake_mountpoint_error:
+ free(buff);
+ free(tmpdir);
+ return NULL;
+}
+
+bool __wrap_probe_config_file(CONFIG_PART *cp)
+{
+ bool ret;
+ probe_config_file_call_count++;
+
+ FILE *test_file = fopen("./test.txt", "a+");
+ if (!test_file)
+ return true;
+
+ fprintf(test_file, "probe_config_file(%s)\n", cp->devpath);
+ fclose(test_file);
+
+ if (asprintf(&cp->mountpoint, "tmpdir") == -1)
+ {
+ cp->not_mounted = true;
+ cp->mountpoint = NULL;
+ return false;
+ }
+ cp->not_mounted = false;
+ ret = __real_probe_config_file(cp);
+
+ free(cp->mountpoint);
+ return ret;
+}
+
+void delete_temp_files(void)
+{
+ char *buffer;
+ while (!STAILQ_EMPTY(&head)) {
+ struct fake_env_file_path *fefp = STAILQ_FIRST(&head);
+
+ if (asprintf(&buffer, "%s/BGENV.DAT", fefp->path) != -1) {
+ remove(buffer);
+ free(buffer);
+ }
+ rmdir(fefp->path);
+ free(fefp->path);
+
+ STAILQ_REMOVE_HEAD(&head, fake_env_file_paths);
+ free(fefp);
+ }
+}
+
+FAKE_VOID_FUNC(ped_device_probe_all);
+FAKE_VALUE_FUNC(PedDevice *, ped_device_get_next, const PedDevice *);
+FAKE_VALUE_FUNC(char *, get_mountpoint, char *);
+
+START_TEST(env_api_fat_test_probe_config_file)
+{
+ bool result;
+
+ RESET_FAKE(ped_device_probe_all);
+ RESET_FAKE(ped_device_get_next);
+ RESET_FAKE(get_mountpoint);
+
+ allocate_fake_devices(1);
+
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ add_fake_partition(0);
+ }
+
+ ped_device_get_next_fake.custom_fake = ped_device_get_next_custom_fake;
+ get_mountpoint_fake.custom_fake = get_mountpoint_custom_fake;
+ probe_config_file_call_count = 0;
+
+ STAILQ_INIT(&head);
+
+ result = bgenv_init();
+
+ delete_temp_files();
+
+ free_fake_devices();
+
+ ck_assert_int_eq(ped_device_probe_all_fake.call_count, 1);
+ ck_assert_int_eq(ped_device_get_next_fake.call_count, 2);
+ ck_assert_int_eq(probe_config_file_call_count, ENV_NUM_CONFIG_PARTS);
+ ck_assert_int_eq(get_mountpoint_fake.call_count, ENV_NUM_CONFIG_PARTS);
+ ck_assert(result == true);
+}
+END_TEST
+
+Suite *ebg_test_suite(void)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create("env_api_fat");
+
+ tc_core = tcase_create("Core");
+ tcase_add_test(tc_core, env_api_fat_test_probe_config_file);
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
diff --git a/tools/tests/test_probe_config_partitions.c b/tools/tests/test_probe_config_partitions.c
new file mode 100644
index 0000000..8dacf14
--- /dev/null
+++ b/tools/tests/test_probe_config_partitions.c
@@ -0,0 +1,99 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (c) Siemens AG, 2017
+ *
+ * Authors:
+ * Andreas Reichel <
andreas.r...@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef ENV_NUM_CONFIG_PARTITIONS
+# define ENV_NUM_CONFIG_PARTITIONS 2
+#endif
+
+#include <stdlib.h>
+#include <check.h>
+#include <fff.h>
+#include <env_api.h>
+#include <env_config_file.h>
+#include <env_config_partitions.h>
+#include <fake_devices.h>
+
+DEFINE_FFF_GLOBALS;
+
+Suite *ebg_test_suite(void);
+
+bool read_env_custom_fake(CONFIG_PART *cp, BG_ENVDATA *env);
+bool read_env(CONFIG_PART *part, BG_ENVDATA *env);
+
+bool read_env_custom_fake(CONFIG_PART *cp, BG_ENVDATA *env)
+{
+ if (!env) {
+ return false;
+ }
+ memset(env, 0, sizeof(BG_ENVDATA));
+ return true;
+}
+
+FAKE_VALUE_FUNC(bool, read_env, CONFIG_PART *, BG_ENVDATA *);
+FAKE_VOID_FUNC(ped_device_probe_all);
+FAKE_VALUE_FUNC(PedDevice *, ped_device_get_next, const PedDevice *);
+
+START_TEST(env_api_fat_test_probe_config_partitions)
+{
+ bool result;
+ /* In this unit test, contents of environment data are
+ * faked to be all zero
+ */
+
+ /* Test if bgenv_init fails if no block devices are found
+ */
+ RESET_FAKE(ped_device_probe_all);
+ RESET_FAKE(ped_device_get_next);
+
+ ped_device_get_next_fake.return_val = NULL;
+
+ result = bgenv_init();
+
+ ck_assert(ped_device_probe_all_fake.call_count == 1);
+ ck_assert(result == false);
+
+ /* Test if bgenv_init fails if a device with two partitions is found
+ * but now config file is there
+ */
+ RESET_FAKE(ped_device_probe_all);
+ RESET_FAKE(ped_device_get_next);
+
+ allocate_fake_devices(1);
+
+ for (int i = 0; i < ENV_NUM_CONFIG_PARTS; i++) {
+ add_fake_partition(0);
+ }
+
+ ped_device_get_next_fake.custom_fake = ped_device_get_next_custom_fake;
+ result = bgenv_init();
+
+ free_fake_devices();
+
+ ck_assert(ped_device_probe_all_fake.call_count == 1);
+ ck_assert(ped_device_get_next_fake.call_count == 2);
+ ck_assert(result == false);
+}
+END_TEST
+
+Suite *ebg_test_suite(void)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create("env_api_fat");
+
+ tc_core = tcase_create("Core");
+ tcase_add_test(tc_core, env_api_fat_test_probe_config_partitions);
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
--
2.14.2