Skip to content
Browse files

sanitycheck: support symbolic links in ZEPHYR_BASE

Fix issue where sanitycheck wrongly assumed tests inside ZEPHYR_BASE
to be outside ZEPHYR_BASE and dropped the prefix in their name. This
happened when:
- ZEPHYR_BASE contains symbolic link(s), and
- relative --testcase-root argument(s) are passed

To generate unique names, TestCase.get_unique(testcase_root) first
checks whether "testcase_root" starts with ZEPHYR_BASE. Either may or
may not include symbolic links so both must be canonicalized before
comparison. While fixing this method, replace explicit forward slash
"/" and string replace with os.path.relpath() and make a couple other
simplifications and minor pydoc fixes.

Add new canonical_zephyr_base = os.path.realpath(ZEPHYR_BASE) constant
and corresponding comments and guidelines.

The most visible effect of this mismatch was sanitycheck dropping the
--testcase-root prefix from the unique name of tests inside
ZEPHYR_BASE. This means some test names could be not unique anymore
and silently overwrite each other's results, example:

 bash# cd zephyr_dir_with_symlink; export ZEPHYR_BASE=$(pwd)
 ./scripts/sanitycheck -T samples/portability/cmsis_rtos_v1 \
                       -T samples/portability/cmsis_rtos_v2

The more systematic and practical consequence (and how I actually
found this) was test outputs landing in unexpected locations.

Signed-off-by: Marc Herbert <>
  • Loading branch information...
marc-hb authored and nashif committed Apr 16, 2019
1 parent 9012960 commit 1c8632cfaad3bbc345137f1c065d0b843a81b3af
Showing with 19 additions and 11 deletions.
  1. +19 −11 scripts/sanitycheck
@@ -209,6 +209,14 @@ if not ZEPHYR_BASE:
sys.stderr.write("$ZEPHYR_BASE environment variable undefined.\n")

# Use this for internal comparisons; that's what canonicalization is
# for. Don't use it when invoking other components of the build system
# to avoid confusing and hard to trace inconsistencies in error messages
# and logs, generated Makefiles, etc. compared to when users invoke these
# components directly.
# Note "normalization" is different from canonicalization, see os.path.
canonical_zephyr_base = os.path.realpath(ZEPHYR_BASE)

sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/"))

@@ -1654,10 +1662,9 @@ class TestCase:
a testcase.yaml can define multiple tests, the canonical name for
the test case is <workdir>/<name>.
@param testcase_root Absolute path to the root directory where
all the test cases live
@param workdir Relative path to the project directory for this
test application from the test_case root.
@param testcase_root os.path.abspath() of one of the --testcase-root
@param workdir Sub-directory of testcase_root where the
.yaml test configuration file was found
@param name Name of this test case, corresponding to the entry name
in the test case configuration file. For many test cases that just
define one test, can be anything and is usually "test". This is
@@ -1703,16 +1710,17 @@ class TestCase:

def get_unique(self, testcase_root, workdir, name):

if ZEPHYR_BASE in testcase_root:
# This is a Zephyr Test, so include path in name for uniqueness
canonical_testcase_root = os.path.realpath(testcase_root)
if canonical_testcase_root.startswith(canonical_zephyr_base):
# This is in ZEPHYR_BASE, so include path in name for uniqueness
# FIXME: We should not depend on path of test for unique names.

zephyr_base = os.path.join(os.path.realpath(ZEPHYR_BASE))
short_path = os.path.normpath(testcase_root.replace(zephyr_base + "/", ""))
relative_tc_root = os.path.relpath(canonical_testcase_root,
short_path = ""
relative_tc_root = ""

unique = os.path.normpath(os.path.join(short_path, workdir, name))
# workdir can be "."
unique = os.path.normpath(os.path.join(relative_tc_root, workdir, name))
return unique

def scan_file(self, inf_name):

0 comments on commit 1c8632c

Please sign in to comment.
You can’t perform that action at this time.