Skip to content

Commit 4d7c60a

Browse files
committed
build: add tests coverage
Signed-off-by: Giuseppe Scrivano <[email protected]>
1 parent 8418412 commit 4d7c60a

File tree

3 files changed

+168
-4
lines changed

3 files changed

+168
-4
lines changed

Makefile.am

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,22 @@ libocispec/libocispec.la:
8686

8787
libcrun_la_SOURCES = $(libcrun_SOURCES)
8888
libcrun_la_CFLAGS = -I $(abs_top_builddir)/libocispec/src -I $(abs_top_srcdir)/libocispec/src -fvisibility=hidden
89-
libcrun_la_LIBADD = libocispec/libocispec.la $(FOUND_LIBS) $(maybe_libyajl.la)
89+
if ENABLE_COVERAGE
90+
libcrun_la_CFLAGS += $(COVERAGE_CFLAGS)
91+
libcrun_la_LDFLAGS = -Wl,--version-script=$(abs_top_srcdir)/libcrun.lds $(COVERAGE_LDFLAGS)
92+
else
9093
libcrun_la_LDFLAGS = -Wl,--version-script=$(abs_top_srcdir)/libcrun.lds
94+
endif
95+
libcrun_la_LIBADD = libocispec/libocispec.la $(FOUND_LIBS) $(maybe_libyajl.la)
9196

9297
# build a version with all the symbols visible for testing
9398
if BUILD_TESTS
9499
libcrun_testing_la_SOURCES = $(libcrun_SOURCES)
95100
libcrun_testing_la_CFLAGS = -I $(abs_top_builddir)/libocispec/src -I $(abs_top_srcdir)/libocispec/src -fvisibility=default
101+
if ENABLE_COVERAGE
102+
libcrun_testing_la_CFLAGS += $(COVERAGE_CFLAGS)
103+
libcrun_testing_la_LDFLAGS = $(COVERAGE_LDFLAGS)
104+
endif
96105
libcrun_testing_la_LIBADD = libocispec/libocispec.la $(maybe_libyajl.la)
97106
endif
98107

@@ -137,16 +146,27 @@ dist-luarock: $(LUACRUN_ROCK)
137146
endif
138147

139148
crun_CFLAGS = -I $(abs_top_builddir)/libocispec/src -I $(abs_top_srcdir)/libocispec/src -D CRUN_LIBDIR="\"$(CRUN_LIBDIR)\""
149+
if ENABLE_COVERAGE
150+
crun_CFLAGS += $(COVERAGE_CFLAGS)
151+
endif
140152
crun_SOURCES = src/crun.c src/run.c src/delete.c src/kill.c src/pause.c src/unpause.c src/oci_features.c src/spec.c \
141153
src/exec.c src/list.c src/create.c src/start.c src/state.c src/update.c src/ps.c \
142154
src/checkpoint.c src/restore.c src/mounts.c src/run_create.c
143155

144156
if DYNLOAD_LIBCRUN
157+
if ENABLE_COVERAGE
158+
crun_LDFLAGS = -Wl,--unresolved-symbols=ignore-all $(CRUN_LDFLAGS) $(COVERAGE_LDFLAGS)
159+
else
145160
crun_LDFLAGS = -Wl,--unresolved-symbols=ignore-all $(CRUN_LDFLAGS)
161+
endif
146162
else
147163
crun_LDADD = libcrun.la $(FOUND_LIBS) $(maybe_libyajl.la)
164+
if ENABLE_COVERAGE
165+
crun_LDFLAGS = $(CRUN_LDFLAGS) $(COVERAGE_LDFLAGS)
166+
else
148167
crun_LDFLAGS = $(CRUN_LDFLAGS)
149168
endif
169+
endif
150170

151171
EXTRA_DIST = COPYING COPYING.libcrun README.md NEWS SECURITY.md rpm/crun.spec autogen.sh \
152172
src/libcrun/blake3/blake3_impl.h src/libcrun/blake3/blake3.h \
@@ -187,6 +207,7 @@ TESTS_LDADD = libcrun_testing.la $(FOUND_LIBS) $(maybe_libyajl.la)
187207

188208
tests_init_LDADD =
189209
tests_init_LDFLAGS = -static-libgcc -all-static
210+
tests_init_CFLAGS = -g -O2
190211
tests_init_SOURCES = tests/init.c
191212

192213
tests_tests_libcrun_utils_CFLAGS = -I $(abs_top_builddir)/libocispec/src -I $(abs_top_srcdir)/libocispec/src -I $(abs_top_builddir)/src -I $(abs_top_srcdir)/src
@@ -338,4 +359,105 @@ clang-format:
338359
shellcheck:
339360
shellcheck autogen.sh build-aux/release.sh tests/run_all_tests.sh tests/*/*.sh contrib/*.sh
340361

341-
.PHONY: coverity sync generate-rust-bindings generate-signals.c generate-mount_flags.c clang-format shellcheck
362+
# Code coverage targets
363+
if ENABLE_COVERAGE
364+
365+
# Clean coverage data
366+
coverage-clean:
367+
@rm -rf coverage-html coverage.info coverage.xml
368+
@find . -name "*.gcda" -delete
369+
@find . -name "*.gcno" -delete
370+
371+
# Reset coverage counters
372+
coverage-reset:
373+
@if test -n "$(LCOV)"; then \
374+
$(LCOV) --zerocounters --directory .; \
375+
fi
376+
377+
# Run tests and collect coverage data
378+
coverage-check: coverage-reset
379+
@echo "Running tests for coverage (single-threaded to avoid race conditions)..."
380+
$(MAKE) -j1 check
381+
@echo "Collecting coverage data..."
382+
383+
# Generate HTML coverage report (preferred method with lcov)
384+
coverage-html: coverage-check
385+
@if test -n "$(LCOV)"; then \
386+
echo "Generating coverage report with lcov..."; \
387+
$(LCOV) --capture --directory . --output-file coverage.info; \
388+
$(LCOV) --remove coverage.info '/usr/*' --output-file coverage.info; \
389+
$(LCOV) --remove coverage.info '*/libocispec/*' --output-file coverage.info; \
390+
$(LCOV) --remove coverage.info '*/tests/test_*.py*' --output-file coverage.info; \
391+
$(LCOV) --remove coverage.info '*/tests/init*' --output-file coverage.info; \
392+
genhtml coverage.info --output-directory coverage-html; \
393+
echo "Coverage report generated in coverage-html/index.html"; \
394+
elif test -n "$(GCOVR)"; then \
395+
echo "Generating coverage report with gcovr..."; \
396+
$(GCOVR) --html --html-details -o coverage.html \
397+
--exclude '/usr/.*' --exclude '.*/libocispec/.*' --exclude '.*/tests/test_.*\.py.*' --exclude '.*/tests/init.*'; \
398+
echo "Coverage report generated in coverage.html"; \
399+
else \
400+
echo "Generating coverage report with gcov..."; \
401+
mkdir -p coverage-html; \
402+
for src in $(libcrun_SOURCES) $(crun_SOURCES); do \
403+
if test -f "$${src}.gcno"; then \
404+
$(GCOV) -o . $$src || true; \
405+
fi; \
406+
done; \
407+
mv *.gcov coverage-html/ 2>/dev/null || true; \
408+
echo "Coverage files generated in coverage-html/"; \
409+
fi
410+
411+
# Generate XML coverage report (for CI tools)
412+
coverage-xml: coverage-check
413+
@if test -n "$(GCOVR)"; then \
414+
echo "Generating XML coverage report with gcovr..."; \
415+
$(GCOVR) --xml -o coverage.xml \
416+
--exclude '/usr/.*' --exclude '.*/libocispec/.*' --exclude '.*/tests/test_.*\.py.*' --exclude '.*/tests/init.*'; \
417+
echo "Coverage report generated in coverage.xml"; \
418+
elif test -n "$(LCOV)"; then \
419+
echo "Generating XML coverage report with lcov..."; \
420+
$(LCOV) --capture --directory . --output-file coverage.info; \
421+
$(LCOV) --remove coverage.info '/usr/*' --output-file coverage.info; \
422+
$(LCOV) --remove coverage.info '*/libocispec/*' --output-file coverage.info; \
423+
$(LCOV) --remove coverage.info '*/tests/test_*.py*' --output-file coverage.info; \
424+
$(LCOV) --remove coverage.info '*/tests/init*' --output-file coverage.info; \
425+
echo "Coverage data collected in coverage.info"; \
426+
else \
427+
echo "XML coverage requires gcovr or lcov"; \
428+
exit 1; \
429+
fi
430+
431+
# Generate coverage summary
432+
coverage-summary: coverage-check
433+
@if test -n "$(LCOV)"; then \
434+
echo "Coverage summary (lcov):"; \
435+
$(LCOV) --capture --directory . --output-file coverage.info; \
436+
$(LCOV) --remove coverage.info '/usr/*' --output-file coverage.info; \
437+
$(LCOV) --remove coverage.info '*/libocispec/*' --output-file coverage.info; \
438+
$(LCOV) --remove coverage.info '*/tests/test_*.py*' --output-file coverage.info; \
439+
$(LCOV) --remove coverage.info '*/tests/init*' --output-file coverage.info; \
440+
$(LCOV) --summary coverage.info; \
441+
elif test -n "$(GCOVR)"; then \
442+
echo "Coverage summary (gcovr):"; \
443+
$(GCOVR) --exclude '/usr/.*' --exclude '.*/libocispec/.*' --exclude '.*/tests/test_.*\.py.*' --exclude '.*/tests/init.*'; \
444+
else \
445+
echo "Coverage summary requires lcov or gcovr"; \
446+
fi
447+
448+
else
449+
450+
coverage-clean:
451+
@echo "Coverage support not enabled. Reconfigure with --enable-coverage"
452+
453+
coverage-reset coverage-check coverage-html coverage-xml coverage-summary:
454+
@echo "Coverage support not enabled. Reconfigure with --enable-coverage"
455+
456+
endif
457+
458+
clean-local: coverage-clean
459+
460+
# Coverage targets must not run in parallel due to race conditions in .gcda file writes
461+
.NOTPARALLEL: coverage-reset coverage-check coverage-html coverage-xml coverage-summary
462+
463+
.PHONY: coverity sync generate-rust-bindings generate-signals.c generate-mount_flags.c clang-format shellcheck coverage-clean coverage-reset coverage-check coverage-html coverage-xml coverage-summary

configure.ac

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,45 @@ if test -z "$GPERF"; then
366366
AC_MSG_NOTICE(gperf not found - cannot rebuild signal parser code)
367367
fi
368368

369+
dnl code coverage
370+
AC_ARG_ENABLE([coverage],
371+
AS_HELP_STRING([--enable-coverage], [Enable code coverage support]),
372+
[enable_coverage=$enableval], [enable_coverage=no])
373+
374+
AS_IF([test "x$enable_coverage" = "xyes"], [
375+
AC_CHECK_TOOL([GCOV], [gcov])
376+
if test -z "$GCOV"; then
377+
AC_MSG_ERROR([gcov is required for code coverage])
378+
fi
379+
380+
AC_CHECK_TOOL([LCOV], [lcov])
381+
AC_CHECK_TOOL([GCOVR], [gcovr])
382+
383+
# Choose the best available coverage tool
384+
if test -n "$LCOV"; then
385+
coverage_tool=lcov
386+
elif test -n "$GCOVR"; then
387+
coverage_tool=gcovr
388+
else
389+
coverage_tool=gcov
390+
fi
391+
392+
AC_MSG_NOTICE([Using $coverage_tool for code coverage reporting])
393+
394+
# Add coverage flags
395+
COVERAGE_CFLAGS="--coverage -g -O0 -fno-inline -fno-inline-small-functions -fno-default-inline"
396+
COVERAGE_LDFLAGS="--coverage"
397+
398+
AC_SUBST([COVERAGE_CFLAGS])
399+
AC_SUBST([COVERAGE_LDFLAGS])
400+
AC_SUBST([GCOV])
401+
AC_SUBST([LCOV])
402+
AC_SUBST([GCOVR])
403+
AC_SUBST([coverage_tool], [$coverage_tool])
404+
])
405+
406+
AM_CONDITIONAL([ENABLE_COVERAGE], [test "x$enable_coverage" = "xyes"])
407+
369408
AC_SEARCH_LIBS([argp_parse], [argp], [], [AC_MSG_ERROR([*** argp functions not found - install libargp or argp_standalone])])
370409

371410
AM_CONDITIONAL([PYTHON_BINDINGS], [test "x$with_python_bindings" = "xyes"])

maint.mk

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,7 +1581,7 @@ init-coverage:
15811581
lcov --directory . --zerocounters
15821582
15831583
COVERAGE_CCOPTS ?= "-g --coverage"
1584-
COVERAGE_OUT ?= doc/coverage
1584+
COVERAGE_OUT ?= docs/coverage
15851585
15861586
build-coverage:
15871587
$(MAKE) $(AM_MAKEFLAGS) CFLAGS=$(COVERAGE_CCOPTS) CXXFLAGS=$(COVERAGE_CCOPTS)
@@ -1594,7 +1594,10 @@ gen-coverage:
15941594
genhtml --output-directory $(COVERAGE_OUT) \
15951595
$(COVERAGE_OUT)/$(PACKAGE).info \
15961596
--highlight --frames --legend \
1597-
--title "$(PACKAGE_NAME)"
1597+
--title "$(PACKAGE_NAME)" \
1598+
--ignore-errors unmapped
1599+
1600+
.NOTPARALLEL: coverage init-coverage build-coverage gen-coverage
15981601
15991602
coverage:
16001603
$(MAKE) init-coverage

0 commit comments

Comments
 (0)