tests: Add build subsystem for unit testing coreboot

Add a subsystem which will be used for writing, building and running
unit tests for different coreboot's modules. This work is built using
Cmocka unit testing framework. Description of what unit testing means
(for the author) and how unit testing framework evaluation was performed
may be found in Documentation/technotes/2020-03-unit-testing-coreboot.md

Makefiles structure is very similar to this used for building coreboot
images. Every directory has its own Makefile.inc were tests' names,
sources, subdirs and multiple other test-related attributes are defined
in form of variables.

Signed-off-by: Jan Dabros <jsd@semihalf.com>
Change-Id: I9b0220b84b9a6e448476ca3eb3ccccc5fb829ad1
Reviewed-on: https://review.coreboot.org/c/coreboot/+/39894
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
Jan Dabros 2020-03-28 00:15:03 +01:00 committed by Patrick Georgi
parent 6449b67427
commit ef1c968374
2 changed files with 155 additions and 0 deletions

View File

@ -141,6 +141,14 @@ NOMKDIR:=1
endif
endif
ifneq ($(filter %-test %-tests,$(MAKECMDGOALS)),)
ifneq ($(filter-out %-test %-tests, $(MAKECMDGOALS)),)
$(error Cannot mix unit-tests targets with other targets)
endif
UNIT_TEST:=1
NOCOMPILE:=
endif
.xcompile: util/xcompile/xcompile
rm -f $@
$< $(XGCCPATH) > $@.tmp
@ -159,7 +167,9 @@ real-all:
@exit 1
else
ifneq ($(UNIT_TEST),1)
include $(DOTCONFIG)
endif
# in addition to the dependency below, create the file if it doesn't exist
# to silence stupid warnings about a file that would be generated anyway.
@ -177,7 +187,9 @@ ifneq ($(CONFIG_MMX),y)
CFLAGS_x86_32 += -mno-mmx
endif
ifneq ($(UNIT_TEST),1)
include toolchain.inc
endif
strip_quotes = $(strip $(subst ",,$(subst \",,$(1))))
# fix makefile syntax highlighting after strip macro \" "))
@ -276,7 +288,14 @@ evaluate_subdirs= \
# collect all object files eligible for building
subdirs:=$(TOPLEVEL)
postinclude-hooks :=
# Don't iterate through Makefile.incs under src/ when building tests
ifneq ($(UNIT_TEST),1)
$(eval $(call evaluate_subdirs))
else
include $(TOPLEVEL)/tests/Makefile.inc
endif
ifeq ($(FAILBUILD),1)
$(error cannot continue build)
endif

136
tests/Makefile.inc Normal file
View File

@ -0,0 +1,136 @@
# SPDX-License-Identifier: GPL-2.0-only
# This file is part of the coreboot project.
testobj = $(obj)/tests
TEST_DEFAULT_CONFIG = $(top)/configs/config.emulation_qemu_x86_i440fx
TEST_DOTCONFIG = $(testobj)/.config
TEST_KCONFIG_AUTOHEADER := $(testobj)/config.h
TEST_KCONFIG_AUTOCONFIG := $(testobj)/auto.conf
TEST_KCONFIG_DEPENDENCIES := $(testobj)/auto.conf.cmd
TEST_KCONFIG_SPLITCONFIG := $(testobj)/config
TEST_KCONFIG_TRISTATE := $(testobj)/tristate.conf
TEST_CFLAGS = -include$(src)/include/kconfig.h \
-include$(src)/commonlib/bsd/include/commonlib/bsd/compiler.h \
-include $(src)/include/rules.h \
# Include generic test mock headers, before original ones
TEST_CFLAGS += -Itests/include/mocks
TEST_CFLAGS += -I$(src)/include -I$(src)/commonlib/include \
-I$(src)/commonlib/bsd/include -I$(src)/arch/x86/include \
# Path for Kconfig autoheader
TEST_CFLAGS += -I$(dir $(TEST_KCONFIG_AUTOHEADER))
TEST_CFLAGS += -std=gnu11 -Os -ffunction-sections -fdata-sections \
-Wl,--gc-sections -fno-builtin
# Link against Cmocka
TEST_LDFLAGS = -lcmocka
# Extra attributes for unit tests, declared per test
attributes:= srcs cflags mocks stage
stages:= decompressor bootblock romstage smm verstage
stages+= ramstage rmodule postcar libagesa
alltests:=
subdirs:= tests/arch tests/commonlib tests/console tests/cpu tests/device
subdirs+= tests/drivers tests/ec tests/lib tests/mainboard
subdirs+= tests/northbridge tests/security tests/soc tests/southbridge
subdirs+= tests/superio tests/vendorcode
define tests-handler
alltests += $(1)$(2)
$(foreach attribute,$(attributes),
$(eval $(1)$(2)-$(attribute) += $($(2)-$(attribute))))
$(foreach attribute,$(attributes),
$(eval $(2)-$(attribute):=))
# Sanity check for stage attribute value
$(eval $(1)$(2)-stage:=$(if $($(1)$(2)-stage),$($(1)$(2)-stage),ramstage))
$(if $(findstring $($(1)$(2)-stage), $(stages)),,
$(error Wrong $(1)$(2)-stage value $($(1)$(2)-stage). \
Check your $(dir $(1)$(2))Makefile.inc))
endef
$(call add-special-class, tests)
$(call evaluate_subdirs)
# Create actual targets for unit test binaries
# $1 - test name
define TEST_CC_template
$($(1)-objs): TEST_CFLAGS+= \
-D__$$(shell echo $$($(1)-stage) | tr '[:lower:]' '[:upper:]')__
$($(1)-objs): $(obj)/$(1)/%.o: $$$$*.c $(TEST_KCONFIG_AUTOHEADER)
mkdir -p $$(dir $$@)
$(HOSTCC) $(HOSTCFLAGS) $$(TEST_CFLAGS) $($(1)-cflags) -MMD \
-MT $$@ -c $$< -o $$@
$($(1)-bin): TEST_LDFLAGS+= $$(foreach mock,$$($(1)-mocks),-Wl,--wrap=$$(mock))
$($(1)-bin): $($(1)-objs)
$(HOSTCC) $$^ $($(1)-cflags) $$(TEST_LDFLAGS) -o $$@
endef
$(foreach test, $(alltests), \
$(eval $(test)-objs:=$(addprefix $(obj)/$(test)/, \
$(patsubst %.c,%.o,$($(test)-srcs)))))
$(foreach test, $(alltests), \
$(eval $(test)-bin:=$(obj)/$(test)/run))
$(foreach test, $(alltests), \
$(eval $(call TEST_CC_template,$(test))))
$(foreach test, $(alltests), \
$(eval all-test-objs+=$($(test)-objs)))
$(foreach test, $(alltests), \
$(eval test-bins+=$($(test)-bin)))
DEPENDENCIES += $(addsuffix .d,$(basename $(all-test-objs)))
-include $(DEPENDENCIES)
# Kconfig targets
$(TEST_DOTCONFIG):
mkdir -p $(dir $@)
cp $(TEST_DEFAULT_CONFIG) $(TEST_DOTCONFIG)
# Don't override default Kconfig variables, since this will affect all
# Kconfig targets. Change them only when calling sub-make instead.
$(TEST_KCONFIG_AUTOHEADER): TEST_KCONFIG_FLAGS:= DOTCONFIG=$(TEST_DOTCONFIG) \
KCONFIG_AUTOHEADER=$(TEST_KCONFIG_AUTOHEADER) \
KCONFIG_AUTOCONFIG=$(TEST_KCONFIG_AUTOCONFIG) \
KCONFIG_DEPENDENCIES=$(TEST_KCONFIG_DEPENDENCIES) \
KCONFIG_SPLITCONFIG=$(TEST_KCONFIG_SPLITCONFIG) \
KCONFIG_TRISTATE=$(TEST_KCONFIG_TRISTATE) \
KBUILD_DEFCONFIG=$(TEST_DEFAULT_CONFIG)
$(TEST_KCONFIG_AUTOHEADER): $(TEST_DOTCONFIG) $(objutil)/kconfig/conf
mkdir -p $(dir $@)
+$(MAKE) $(TEST_KCONFIG_FLAGS) olddefconfig
+$(MAKE) $(TEST_KCONFIG_FLAGS) silentoldconfig
$(TEST_KCONFIG_AUTOCONFIG): $(TEST_KCONFIG_AUTOHEADER)
true
.PHONY: $(alltests) $(addprefix clean-,$(alltests))
.PHONY: unit-tests build-unit-tests run-unit-tests clean-unit-tests
$(alltests): $$($$(@)-bin)
./$^
unit-tests: build-unit-tests run-unit-tests
build-unit-tests: $(test-bins)
run-unit-tests: $(alltests)
echo "**********************"
echo " ALL TESTS PASSED"
echo "**********************"
$(addprefix clean-,$(alltests)): clean-%:
rm -rf $(obj)/$*
clean-unit-tests:
rm -rf $(testobj)