Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37655514
en ru br
Репозитории ALT

Группа :: Система/Библиотеки
Пакет: libqb

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: 03-tests-new-sort-of-tests-dubbed-functional-cover-link.patch
Скачать


From 3df0138ba57e274b8c8065739870b1529b95e087 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
Date: Fri, 6 Oct 2017 17:17:26 +0200
Subject: [PATCH 3/6] tests: new sort of tests dubbed "functional", cover
 linker vs. logging
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
These are for quick manual sanity checking, assuming the target audience
-- maintainers -- are clear on the context of use and the purpose
(perhaps with the help of static files for comparison and/or additional
checking harness, usually available through "make check", but not to be
confused with regular unit + broader tests).  These test are meant to be
compiled on demand only, not during the standard building routine, for
which a trick leveraging GNUmakefile-Makefile precedence with GNU make
was devised (GNU make/gmake already required by configure script for
other reasons [some pattern-based matching not available with FreeBSD's
default "make", IIRC], so this introduces no new build dependency).
The respective new tests are meant to simulate logging variants in two
different library consumption models:
  a. regular: linking against system-wide library
  b. developmental: consuming library from a local sub-checkout tree,
                    using libtool conventions and hence attaching the
                    library through libqb.la intermediate library
                    descriptor of libtool
and between up to three possibly affected logging system participants
(discrete compilation units):
  1. libqb itself will emit log messages in boundary conditions or
     for tracing purposes
  2. client program that consumes libqb's logging API directly
  3. ditto, but the client program furthermore links with a library
     (referred to as "interlib") that itself exercises the logging
     API (it's also linked with libqb) -- through induction, this
     should cover whole class of N interlib cases
Especially the latter perspective makes for a test matrix to possibly
(hopefully) demonstrate a fix allowing to cope with the changed
behaviour of ld from binutils 2.29+ wrt. boundaries denoting symbols for
a (custom) orphan section that are no longer externally visible.  Such
commit is in the pipeline...
Developmental consumption model (a.) is now also tested automatically
in Travis CI runs and as a part of %check within upstream-suggested
libqb.spec for RPM packaging, whereas the regular one (b.) serves as
a building block for new log_test_mock.sh runner of said test matrix
-- it iterates through all the possible permutations of linker-imposed
implicit visibility of mentioned symbols between various affected
linkage sides (see 1. - 3. above) so as to demonstrate a/ the impact
of the problem (see table below), and subsequently b/ that the fix is
effective in all these situations (updated table will be provided as
well) once it lands.
Current state for this matrix, in which participants 1. - 3. map like:
  1. ~ libqb(Y)
  2. ~ "direct"
  3. ~ libX(Y)  [a.k.a. interlib]
and where "X(Y)" denotes "X linked with linker Y":
  X(a) .. ld.bfd < 2.29
  X(b) .. ld.bfd = 2.29 (and only 2.29),
goes like this:
+=========+=========+=========+=========+=========+=========+=========+
#client(x)#        libqb(a) usage       #        libqb(b) usage       #
#   vvv   #---------+---------+---------+---------+---------+---------+
#    V    #  direct | libX(a) : libX(b) #  direct | libX(a) : libX(b) #
+=========+=========+=========+=========+=========+=========+=========+
#  x = a  #   OK    |   OK    : BAD[*2] # BAD[*1] | BAD[*D] : BAD[*3] #
#  x = b  # BAD[*A] | BAD[*B] : BAD[*C] # BAD[*1] | BAD[*C] : BAD[*3] #
+=========+=========+=========+=========+=========+=========+=========+
whereas if we swap 2.29 for 2.29.1, i.e., X(b) .. ld.bfd = 2.29.1, we
can observe a somewhat simpler story (DEP ~ "depends"):
+=========+=========+=========+=========+=========+=========+=========+
#client(x)#        libqb(a) usage       #        libqb(b) usage       #
#   vvv   #---------+---------+---------+---------+---------+---------+
#    V    #  direct | libX(a) : libX(b) #  direct | libX(a) : libX(b) #
+=========+=========+=========+=========+=========+=========+=========+
#  x = a  #   OK    |   OK    : DEP[*J] # BAD[*1] | BAD[*1] : BAD[*L] #
#  x = b  # DEP[*I] | DEP[*I] : DEP[*K] # BAD[*1] | BAD[*1] : BAD[*L] #
+=========+=========+=========+=========+=========+=========+=========+
[*1] client logging not working
[*2] interlib logging not working
[*3] both client and interlib logging not working
[*A] boils down to [*1], unless QB_LOG_INIT_DATA used on client side,
     which fails on 'non-empty callsite section' assertion
[*B] boils down to [*1], unless QB_LOG_INIT_DATA used on interlib side,
     which fails on 'non-empty callsite section' assertion
[*C] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side,
     which fails on 'non-empty callsite section' assertion
[*D] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side,
     which makes it boil down just to [*1] (hypothesis: mere internal
     self-reference to the section's boundary symbols makes them
     overcome some kind of symbol garbage collection at the linkage
     stage, so they are exposed even they wouldn't be otherwise as
     demonstrated with the initial, plain case of [*3])
[*I] boils down to [*1], unless QB_LOG_INIT_DATA used on client side,
     which makes it, likely through self-reference keepalive (see
     below) work OK
[*J] boils down to [*2], unless QB_LOG_INIT_DATA used on interlib side,
     which makes it, likely through self-reference keepalive (see
     below) work OK
[*K] boils down to [*3], unless QB_LOG_INIT_DATA used on both client
     and interlib side, which makes it, likely through self-reference
     keepalive (see below) work OK  (it's expected that this a mere
     composite of situations [*I] and [*J] with consequences as stated)
[*L] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side
     (sufficient?), which makes it, likely through self-reference
     keepalive (see below) boil down just to [*1]
Note: as observed with [*D] case (libqb linked with ld.bfd < 2.29
whereas interlib and its client linked with ld.bfd = 2.29), the exact
availability of a working logging doesn't depend solely on the linkers
in question, but generally (further investigation out of scope) the
conclusion is that when 2.29 ld.bfd is involved somewhere in the chain
of logging-related discrete compilation units, also (self-)referencing
of the section's boundary denoting symbols is a deciding factor whether
particular logging source will be honored.  This may be a result of
some internal linkage garbage collection mechanisms involved.
Anyway, it is supposed that the fix to broken-by-linkage logging can be
proclaimed complete once all combinations pass barring QB_LOG_INIT_DATA
usage (incurring the mentioned active referential use of the symbols),
along with a spin using it everywhere for good measure.
For another level of the analysis depth, one can further play with
combinations of -n{sc,cl,il} options (explained upon -h switch) to
log_test_mock.sh (taking an oracle, this is added mostly to justify
the upcoming self-check test change because linker-script-based
workaround for newer linkers will cause the section boundary symbols
to be present regardless if that section is utilized, leading to
a self-inflicted breakage due to these empty section symbols suddenly
winning in the symbol resolution mechanism).
Signed-off-by: Jan Pokornц╫ <jpokorny@redhat.com>
---
 configure.ac                                  |   7 +-
 libqb.spec.in                                 |   3 +-
 tests/Makefile.am                             |   3 +
 tests/functional/GNUmakefile                  |  20 ++
 tests/functional/Makefile.am                  |  23 ++
 tests/functional/log.am                       |  49 ++++
 tests/functional/log_client.c                 |  88 ++++++++
 tests/functional/log_external/Makefile.am     |  23 ++
 tests/functional/log_interlib.c               |  70 ++++++
 tests/functional/log_interlib_client.c        |  68 ++++++
 tests/functional/log_internal/Makefile.am     |  23 ++
 tests/functional/log_test_client.err          |   2 +
 tests/functional/log_test_client.sh           |  30 +++
 tests/functional/log_test_interlib_client.err |   4 +
 tests/functional/log_test_interlib_client.sh  |  33 +++
 tests/functional/log_test_mock.sh             | 310 ++++++++++++++++++++++++++
 18 files changed, 767 insertions(+), 4 deletions(-)
 create mode 100644 tests/functional/GNUmakefile
 create mode 100644 tests/functional/Makefile.am
 create mode 100644 tests/functional/log.am
 create mode 100644 tests/functional/log_client.c
 create mode 100644 tests/functional/log_external/Makefile.am
 create mode 100644 tests/functional/log_interlib.c
 create mode 100644 tests/functional/log_interlib_client.c
 create mode 100644 tests/functional/log_internal/Makefile.am
 create mode 100644 tests/functional/log_test_client.err
 create mode 100755 tests/functional/log_test_client.sh
 create mode 100644 tests/functional/log_test_interlib_client.err
 create mode 100755 tests/functional/log_test_interlib_client.sh
 create mode 100755 tests/functional/log_test_mock.sh
diff --git a/configure.ac b/configure.ac
index 478194c..274b49c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -13,7 +13,7 @@ AC_CONFIG_SRCDIR([lib/ringbuffer.c])
 AC_CONFIG_HEADERS([include/config.h include/qb/qbconfig.h])
 AC_USE_SYSTEM_EXTENSIONS
 
-AM_INIT_AUTOMAKE([-Wno-portability dist-xz])
+AM_INIT_AUTOMAKE([-Wno-portability dist-xz subdir-objects])
 dnl automake >= 1.11 offers --enable-silent-rules for suppressing the output from
 dnl normal compilation.  When a failure occurs, it will then display the full
 dnl command line
@@ -717,6 +717,9 @@ AC_CONFIG_FILES([Makefile
 		 lib/libqb.pc
 		 tools/Makefile
 		 tests/Makefile
+		 tests/functional/Makefile
+		 tests/functional/log_external/Makefile
+		 tests/functional/log_internal/Makefile
 		 tests/test.conf
 		 examples/Makefile
 		 docs/Makefile
@@ -724,6 +727,8 @@ AC_CONFIG_FILES([Makefile
 		 docs/html.dox
 		 docs/man.dox])
 
+AC_CONFIG_LINKS([tests/functional/GNUmakefile:tests/functional/GNUmakefile])
+
 AC_OUTPUT
 
 AC_MSG_RESULT([])
diff --git a/libqb.spec.in b/libqb.spec.in
index 8320982..cd7fd0f 100644
--- a/libqb.spec.in
+++ b/libqb.spec.in
@@ -31,7 +31,8 @@ make %{?_smp_mflags}
 
 %if 0%{?with_check}
 %check
-VERBOSE=1 make check
+make V=1 check \
+  && make -C tests/functional/log_internal V=1 check
 %endif
 
 %install
diff --git a/tests/Makefile.am b/tests/Makefile.am
index fe54741..df1af81 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -20,6 +20,9 @@
 MAINTAINERCLEANFILES = Makefile.in
 EXTRA_DIST =
 CLEANFILES =
+
+SUBDIRS = functional
+
 AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
 
 noinst_PROGRAMS = bmc bmcpt bms rbreader rbwriter \
diff --git a/tests/functional/GNUmakefile b/tests/functional/GNUmakefile
new file mode 100644
index 0000000..1b9de81
--- /dev/null
+++ b/tests/functional/GNUmakefile
@@ -0,0 +1,20 @@
+all check:
+	# do not trigger automatically, it's for on-demand use
+	@echo "Use 'make $@' within particular subdirectories"
+install: force
+	# definitely not desired to install anything from this subtree
+distclean:
+	# following is a nasty hack to keep "make distclean" succeeding
+	# (problem mostly arises from shared object files and hence shared
+	# compiler-generated makefile includes which are swiped when
+	# processing one subdir and missing as hard error for the other)
+	@$(MAKE) -C log_external $@
+	@mkdir .deps
+	@touch .deps/log_client.Po .deps/log_interlib.Plo .deps/log_interlib_client.Po
+	@$(MAKE) -C log_internal $@
+	@$(MAKE) -f Makefile $@ SUBDIRS=
+%: force
+	@$(MAKE) -f Makefile $@
+force: ;
+
+.PHONY: check distclean force install
diff --git a/tests/functional/Makefile.am b/tests/functional/Makefile.am
new file mode 100644
index 0000000..0d34ae8
--- /dev/null
+++ b/tests/functional/Makefile.am
@@ -0,0 +1,23 @@
+# Copyright 2017 Red Hat, Inc.
+#
+# Authors: Jan Pokorny <jpokorny@redhat.com>
+#
+# This file is part of libqb.
+#
+# libqb is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# libqb is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+
+MAINTAINERCLEANFILES = Makefile.in
+EXTRA_DIST = GNUmakefile log_test_client.err log_test_interlib_client.err \
+             log_test_client.sh log_test_interlib_client.sh log_test_mock.sh
+SUBDIRS = log_external log_internal
diff --git a/tests/functional/log.am b/tests/functional/log.am
new file mode 100644
index 0000000..e8e4740
--- /dev/null
+++ b/tests/functional/log.am
@@ -0,0 +1,49 @@
+# Copyright 2017 Red Hat, Inc.
+#
+# Author: Jan Pokorny <jpokorny@redhat.com>
+#
+# This file is part of libqb.
+#
+# libqb is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# libqb is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+
+MAINTAINERCLEANFILES = Makefile.in
+CLEANFILES = log_test_client.err.real log_test_interlib_client.err.real
+
+AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
+
+noinst_PROGRAMS = log_client log_interlib_client
+# cannot use {check,noinst}_LTLIBRARIES because it leads to solely static lib
+# (this won't get installed anyway, thanks to GNUmakefile rule)
+lib_LTLIBRARIES = liblog_inter.la
+
+log_client_SOURCES = ../log_client.c
+# log_client_LDFLAGS/log_client_LDADD to be delivered by the base Makefile.am
+
+liblog_inter_la_SOURCES = ../log_interlib.c
+liblog_inter_la_LDFLAGS = -shared
+# liblog_inter_la_LIBADD to be delivered by the base Makefile.am
+
+log_interlib_client_SOURCES = ../log_interlib_client.c
+# this transitively shares link dependencies with liblog_inter.la itself
+log_interlib_client_LDADD = $(builddir)/liblog_inter.la
+
+# actual 'make check' auxiliary definitions
+TESTS = ../log_test_client.sh ../log_test_interlib_client.sh
+TEST_EXTENSIONS = .sh
+log_test.log: $(check_PROGRAMS)
+
+../log_test_client.log: log_client
+../log_test_interlib_client.log: log_interlib_client
+
+# vim: ft=automake
diff --git a/tests/functional/log_client.c b/tests/functional/log_client.c
new file mode 100644
index 0000000..c60d657
--- /dev/null
+++ b/tests/functional/log_client.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Pokorny <jpokorny@redhat.com>
+ *
+ * This file is part of libqb.
+ *
+ * libqb is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * libqb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "os_base.h"
+#include <qb/qblog.h>
+
+#ifndef NSELFCHECK
+QB_LOG_INIT_DATA(linker_contra_log);
+#endif
+
+static const char *
+my_tags_stringify(uint32_t tags)
+{
+	if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
+		return "libqb";
+	} else {
+		return "MAIN";
+	}
+}
+
+int32_t
+main(int32_t argc, char *argv[])
+{
+	int tmpfile_fd;
+	struct stat tmpfile_stat;
+	char *tmpfile_buf = strdup("linker-log-XXXXXX");
+
+	qb_log_init("linker-contra-log", LOG_USER, LOG_INFO);
+	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
+	qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
+			  QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
+	qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
+
+	qb_log_tags_stringify_fn_set(my_tags_stringify);
+	qb_log_format_set(QB_LOG_STDERR, "[%5g|%p] %f:%l:%b");
+
+#if 0
+	printf("--\n");
+	qb_log_callsites_dump();
+	printf("--\n");
+#endif
+
+#ifndef NLOG
+	/* Casual test of "user-space" logging. */
+	qb_log(LOG_DEBUG, "hello");
+#endif
+
+	/* And now of "library-space" logging, i.e., let libqb generated
+	   an error message on its own behalf, first to see if it will be
+	   logged at all, second if it will be distinguished properly.
+	   The trigger here is as simple as trying to print non-existing
+	   blackbox file. */
+	tmpfile_fd = mkstemp(tmpfile_buf);
+	if (tmpfile_fd == -1) {
+		qb_perror(LOG_ERR, "creating temporary file");
+		exit(EXIT_FAILURE);
+	}
+	unlink(tmpfile_buf);
+	close(tmpfile_fd);
+#if 0
+	if (stat(tmpfile_buf, &tmpfile_stat) == -1) {
+		qb_perror(LOG_ERR, "stat'ing nonexistent temporary file");
+		exit(EXIT_FAILURE);
+	}
+#endif
+	qb_log_blackbox_print_from_file(tmpfile_buf);
+	free(tmpfile_buf);
+	qb_log_fini();
+}
diff --git a/tests/functional/log_external/Makefile.am b/tests/functional/log_external/Makefile.am
new file mode 100644
index 0000000..36aa0af
--- /dev/null
+++ b/tests/functional/log_external/Makefile.am
@@ -0,0 +1,23 @@
+# Copyright 2017 Red Hat, Inc.
+#
+# Author: Jan Pokorny <jpokorny@redhat.com>
+#
+# This file is part of libqb.
+#
+# libqb is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# libqb is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+
+include ../log.am
+
+log_client_LDFLAGS = -lqb
+liblog_inter_la_LIBADD = -lqb
diff --git a/tests/functional/log_interlib.c b/tests/functional/log_interlib.c
new file mode 100644
index 0000000..228a339
--- /dev/null
+++ b/tests/functional/log_interlib.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Pokorny <jpokorny@redhat.com>
+ *
+ * This file is part of libqb.
+ *
+ * libqb is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * libqb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "os_base.h"
+#include <qb/qblog.h>
+
+#ifndef NSELFCHECK
+QB_LOG_INIT_DATA(linker_contra_log_lib);
+#endif
+
+void foo(void);
+
+void
+foo(void)
+{
+	int tmpfile_fd;
+	struct stat tmpfile_stat;
+	char *tmpfile_buf = strdup("linker-log-XXXXXX");
+
+#if 0
+	printf("--\n");
+	qb_log_callsites_dump();
+	printf("--\n");
+#endif
+
+#ifndef NLIBLOG
+	/* Casual test of "user-space" logging. */
+	qb_log(LOG_INFO, "aloha");
+#endif
+
+	/* And now of "library-space" logging, i.e., let libqb generated
+	   an error message on its own behalf, first to see if it will be
+	   logged at all, second if it will be distinguished properly.
+	   The trigger here is as simple as trying to print non-existing
+	   blackbox file. */
+	tmpfile_fd = mkstemp(tmpfile_buf);
+	if (tmpfile_fd == -1) {
+		qb_perror(LOG_ERR, "creating temporary file");
+		exit(EXIT_FAILURE);
+	}
+	unlink(tmpfile_buf);
+	close(tmpfile_fd);
+#if 0
+	if (stat(tmpfile_buf, &tmpfile_stat) == -1) {
+		qb_perror(LOG_ERR, "stat'ing nonexistent temporary file");
+		exit(EXIT_FAILURE);
+	}
+#endif
+	qb_log_blackbox_print_from_file(tmpfile_buf);
+	free(tmpfile_buf);
+}
diff --git a/tests/functional/log_interlib_client.c b/tests/functional/log_interlib_client.c
new file mode 100644
index 0000000..820df67
--- /dev/null
+++ b/tests/functional/log_interlib_client.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Pokorny <jpokorny@redhat.com>
+ *
+ * This file is part of libqb.
+ *
+ * libqb is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * libqb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "os_base.h"
+#include <qb/qblog.h>
+
+#ifndef NSELFCHECK
+QB_LOG_INIT_DATA(linker_contra_log_lib_user);
+#endif
+
+void foo(void);
+
+static const char *
+my_tags_stringify(uint32_t tags)
+{
+	if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
+		return "libqb";
+	} else {
+		return "MAIN";
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	qb_log_init("linker-contra-log", LOG_USER, LOG_INFO);
+	qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
+	qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
+			  QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
+	qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
+
+	qb_log_tags_stringify_fn_set(my_tags_stringify);
+	qb_log_format_set(QB_LOG_STDERR, "[%5g|%p] %f:%l:%b");
+
+#if 0
+	printf("--\n");
+	qb_log_callsites_dump();
+	printf("--\n");
+#endif
+
+#ifndef NLOG
+	qb_log(LOG_INFO, "BEFORE");
+#endif
+	foo();
+#ifndef NLOG
+	qb_log(LOG_INFO, "AFTER");
+#endif
+	qb_log_fini();
+}
diff --git a/tests/functional/log_internal/Makefile.am b/tests/functional/log_internal/Makefile.am
new file mode 100644
index 0000000..697cee2
--- /dev/null
+++ b/tests/functional/log_internal/Makefile.am
@@ -0,0 +1,23 @@
+# Copyright 2017 Red Hat, Inc.
+#
+# Author: Jan Pokorny <jpokorny@redhat.com>
+#
+# This file is part of libqb.
+#
+# libqb is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# libqb is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+
+include ../log.am
+
+log_client_LDADD = $(top_builddir)/lib/libqb.la
+liblog_inter_la_LIBADD = $(top_builddir)/lib/libqb.la
diff --git a/tests/functional/log_test_client.err b/tests/functional/log_test_client.err
new file mode 100644
index 0000000..cb0ff3c
--- /dev/null
+++ b/tests/functional/log_test_client.err
@@ -0,0 +1,2 @@
+[MAIN |debug] ../log_client.c:64:hello
+[libqb|error] log_blackbox.c:196:qb_log_blackbox_print_from_file: No such file or directory (2)
diff --git a/tests/functional/log_test_client.sh b/tests/functional/log_test_client.sh
new file mode 100755
index 0000000..17e9254
--- /dev/null
+++ b/tests/functional/log_test_client.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Copyright 2017 Red Hat, Inc.
+#
+# Author: Jan Pokorny <jpokorny@redhat.com>
+#
+# This file is part of libqb.
+#
+# libqb is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# libqb is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+
+./log_client >/dev/null 2>log_test_client.err.real
+
+_pipeline='cat ../log_test_client.err'
+case "${CPPFLAGS}" in
+	*-DNLOG*)
+		_pipeline="${_pipeline} | \
+		           grep -Ev '^\[MAIN |info] \.\./log_client\.c'";;
+esac
+
+eval "${_pipeline}" | diff -u - log_test_client.err.real
diff --git a/tests/functional/log_test_interlib_client.err b/tests/functional/log_test_interlib_client.err
new file mode 100644
index 0000000..dc0de9c
--- /dev/null
+++ b/tests/functional/log_test_interlib_client.err
@@ -0,0 +1,4 @@
+[MAIN |info] ../log_interlib_client.c:61:BEFORE
+[MAIN |info] ../log_interlib.c:47:aloha
+[libqb|error] log_blackbox.c:196:qb_log_blackbox_print_from_file: No such file or directory (2)
+[MAIN |info] ../log_interlib_client.c:65:AFTER
diff --git a/tests/functional/log_test_interlib_client.sh b/tests/functional/log_test_interlib_client.sh
new file mode 100755
index 0000000..e066cae
--- /dev/null
+++ b/tests/functional/log_test_interlib_client.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Copyright 2017 Red Hat, Inc.
+#
+# Author: Jan Pokorny <jpokorny@redhat.com>
+#
+# This file is part of libqb.
+#
+# libqb is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# libqb is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+
+./log_interlib_client >/dev/null 2>log_test_interlib_client.err.real
+
+_pipeline='cat ../log_test_interlib_client.err'
+case "${CPPFLAGS}" in
+	*-DNLOG*)
+		_pipeline="${_pipeline} | \
+		           grep -Ev '^\[MAIN \|info] \.\./log_interlib_client\.c'";;
+	*-DNLIBLOG*)
+		_pipeline="${_pipeline} | \
+		           grep -Ev '^\[MAIN \|info\] \.\./log_interlib\.c'";;
+esac
+
+eval "${_pipeline}" | diff -u - log_test_interlib_client.err.real
diff --git a/tests/functional/log_test_mock.sh b/tests/functional/log_test_mock.sh
new file mode 100755
index 0000000..145b9f4
--- /dev/null
+++ b/tests/functional/log_test_mock.sh
@@ -0,0 +1,310 @@
+#!/bin/sh
+# Copyright 2017 Red Hat, Inc.
+#
+# Author: Jan Pokorny <jpokorny@redhat.com>
+#
+# This file is part of libqb.
+#
+# libqb is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# libqb is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with libqb.  If not, see <http://www.gnu.org/licenses/>.
+
+# Given the source RPM for libqb, this will run through the basic test matrix
+# so as to figure out the outcomes for particular linker (pre-2.29 and 2.29+
+# differing in visibility of orphan section delimiting boundary symbols and
+# hence possibly causing harm to the logging facility of libqb) being used
+# for particular part of the composite logging system (libqb itself,
+# it's direct client / (client library + it's own client that uses logging)
+# as well).  While this is tailored to Fedora, it should be possible to
+# run this testsuite wherever following is present:
+#
+#   - rpm (for parsing archive name embedded in libqb.src.rpm [note that
+#     rpm2cpio is part of rpm package as well] because the extracted dir
+#     follows the same naming, which we need to know)
+#   - mock (https://github.com/rpm-software-management/mock/)
+#     + dependencies + fedora-27-${arch} configuration for mock
+#     (or whatever other configuration if some variables below are
+#     changed appropriately)
+#   - koji (https://pagure.io/koji/) + dependencies (but binutils packages
+#     can be precached when downloaded from https://koji.fedoraproject.org/
+#     manually)
+#   - internet connection (but see the above statement for koji, and
+#     possibly the full package set within the build'n'test underlying
+#     container can be precached without further details on "how")
+#   - commons (coreutils, findutils, sed, ...)
+#
+# The testsuite will not mangle with your host system as mock spawns
+# it's somewhat private container for be worked with under the hood.
+#
+# Note that in order not to get mad when entering the root password anytime
+# mock is invoked, you can add the user initiating the test run to the
+# 'mock' group.  Be aware of the associated security risks, though:
+# https://github.com/rpm-software-management/mock/wiki#setup
+
+set -eu
+
+# change following as suitable
+
+arch=x86_64
+mock_args="-r fedora-27-${arch}"
+pkg_binutils_228=binutils-2.28-14.fc27
+#pkg_binutils_228=binutils-2.27-23.fc27  # alternatively test with 2.27 ...
+pkg_binutils_229=binutils-2.29-6.fc27
+#pkg_binutils_229=binutils-2.29.1-2.fc28  # alternatively test with 2.29.1
+
+#
+# prettified reporters
+#
+
+do_progress () { printf "\x1b[7m%s\x1b[0m\n" "$*"; }
+do_info () { printf "\x1b[36mINFO: %s\x1b[0m\n" "$*"; }
+do_warn () { printf "\x1b[31mWARNING: %s\x1b[0m\n" "$*"; }
+do_die () { printf "\x1b[31mFATAL: %s\x1b[0m\n" "$*"; exit 1; }
+
+#
+# actual building blocks
+#
+
+# $1, ... $N: packages (and possibly related subpackages) to be downloaded
+do_download () {
+	while test $# -gt 0; do
+		if test -d "_pkgs/$1" 2>/dev/null; then
+			do_info "$1 already downloaded"
+			shift; continue
+		fi
+		mkdir -p "_pkgs/$1"
+		( cd "_pkgs/$1" && koji download-build --arch="${arch}" "$1" )
+		shift
+	done
+}
+
+# $1, ... $N: descriptors of packages to be installed
+do_install () {
+	while test $# -gt 0; do
+		if test -d "_pkgs/$1" 2>/dev/null; then
+			do_install_inner "_pkgs/$1"/*.rpm
+		else
+			do_warn "$1 is not downloaded, hence skipped"
+		fi
+		shift
+	done
+}
+
+# $1, ... $N: concrete packages to be installed
+do_install_inner () {
+	_remove_cmd="mock ${mock_args} -- shell \"rpm --nodeps --erase"
+	_install_cmd="mock ${mock_args}"
+	while test $# -gt 0; do
+		case "$1" in
+		*.src.rpm|*-debuginfo*|*-debugsource*) ;;
+		*)
+			_pkg_name="$(basename "$1" | sed 's|\(-[0-9].*\)||')"
+			_remove_cmd="${_remove_cmd} \'${_pkg_name}\'"
+			_install_cmd="${_install_cmd} --install \"$1\"";;
+		esac
+		shift
+	done
+	eval "${_remove_cmd}\"" || :  # extra quotation mark intentional
+	eval "${_install_cmd}"
+}
+
+# $1: full path of srpm to be rebuilt
+# $2: %{dist} macro for rpmbuild (distinguishing the builds)
+do_buildsrpm () {
+	_pkg_descriptor="$(basename "$1" | sed 's|\.src\.rpm$||')"
+	# need to prune due to possible duplicates caused by differing %{dist}
+	rm -f -- "_pkgs/${_pkg_descriptor}"/*
+	mock ${mock_args} -Nn --define "dist $2" --define '_without_check 1' \
+	  --resultdir "_pkgs/${_pkg_descriptor}" --rebuild "$1"
+}
+
+# $1: full path srpm to be rebuilt
+# $2: extra (presumably) variable assignments for the make goal invocation
+do_compile_interlib () {
+	mock ${mock_args} --shell \
+		"find \"builddir/build/BUILD/$1/tests/functional\" \
+		\( -name log_internal -o -name '*.c' \) -prune \
+		-o -name '*liblog_inter*' \
+		-exec rm -- {} \;"
+	mock ${mock_args} --shell "( cd \"builddir/build/BUILD/$1\"; ./configure )"
+	mock ${mock_args} --shell \
+		"make -C \"builddir/build/BUILD/$1/tests/functional/log_external\" \
+		liblog_inter.la $2"
+}
+
+# $1: full path srpm to be rebuilt
+# $2: which type of client to work with (client/interclient)
+# $3: base (on-host) directory for test results
+# $4: output file to capture particular test result
+# $5: extra (presumably) variable assignments for the make goal invocation
+do_compile_and_test_client () {
+	_result=$4
+	case "$2" in
+	interclient)
+		_logfile=log_test_interlib_client
+		mock ${mock_args} --shell \
+			"find \"builddir/build/BUILD/$1/tests/functional\" \
+			\( -name log_internal -o -name '*.err' -o -name '*.c' \) -prune \
+			-o \( -name '*log_interlib_client*' -o -name \"${_logfile}.log\" \) \
+			-exec rm -- {} \;"
+		;;
+	client|*)
+		_logfile=log_test_client
+		mock ${mock_args} --shell \
+			"find \"builddir/build/BUILD/$1/tests/functional\" \
+			\( -name log_internal -o -name '*.err' -o -name '*.c' \) -prune \
+			-o \( -name '*log_client*' -o -name \"${_logfile}.log\" \) \
+			-exec rm -- {} \;"
+		;;
+	esac
+	mock ${mock_args} --shell "( cd \"builddir/build/BUILD/$1\"; ./configure )"
+	mock ${mock_args} --shell \
+		"make -C \"builddir/build/BUILD/$1/tests/functional/log_external\" \
+		check-TESTS \"TESTS=../${_logfile}.sh\" $5" \
+	  && _result="${_result}_good" \
+	  || _result="${_result}_bad"
+	mock ${mock_args} --copyout \
+		"builddir/build/BUILD/$1/tests/functional/log_external/test-suite.log" \
+		"$3/${_result}"
+}
+
+do_shell () {
+	mock ${mock_args} --shell
+}
+
+# $1, ... $N: "argv"
+do_proceed () {
+
+	_makevars=
+	_resultsdir_tag=
+	_selfcheck=1
+	_clientlogging=1
+	_interliblogging=1
+	while :; do
+		case "$1" in
+		shell) shift; do_shell "$@"; return;;
+		-nsc) _resultsdir_tag="${_resultsdir_tag}$1"; shift; _selfcheck=0;;
+		-ncl) _resultsdir_tag="${_resultsdir_tag}$1"; shift; _clientlogging=0;;
+		-nil) _resultsdir_tag="${_resultsdir_tag}$1"; shift; _interliblogging=0;;
+		-*) do_die "Uknown option: $1";;
+		*) break;;
+		esac
+	done
+
+	if test -n "${_resultsdir_tag}"; then
+		_makevars="CPPFLAGS=\"$(test "${_selfcheck}" -eq 1 || printf %s ' -DNSELFCHECK') \
+		           $(test "${_clientlogging}" -eq 1 || printf %s ' -DNLOG') \
+		           $(test "${_interliblogging}" -eq 1 || printf %s ' -DNLIBLOG')\""
+		_makevars=$(echo ${_makevars})
+	fi
+
+	test -s "$1" || do_die "Not an input file: $1"
+	_libqb_descriptor_path="$1"
+	_libqb_descriptor="$(basename "${_libqb_descriptor_path}" \
+	                     | sed 's|\.src\.rpm$||')"
+	_libqb_descriptor_archive="$(rpm -q --qf '[%{FILENAMES}\n]' \
+	                             -p "${_libqb_descriptor_path}" \
+	                             | sed -n '/\.tar/{s|\.tar\.[^.]*$||;p;q}')"
+
+	_resultsdir="_results/$(date '+%y%m%d_%H%M%S')_${_libqb_descriptor}${_resultsdir_tag}"
+	mkdir -p "${_resultsdir}"
+	rm -f -- "${_resultsdir}/*"
+
+	_dist=
+	_outfile=
+	_outfile_client=
+	_outfile_qb=
+
+	do_download "${pkg_binutils_228}" "${pkg_binutils_229}"
+
+	for _pkg_binutils_libqb in "${pkg_binutils_228}" "${pkg_binutils_229}"; do
+
+		case "${_pkg_binutils_libqb}" in
+		${pkg_binutils_228}) _outfile_qb="qb+"; _dist=.binutils228;;
+		${pkg_binutils_229}) _outfile_qb="qb-"; _dist=.binutils229;;
+		*) _outfile_qb="?";;
+		esac
+
+		do_progress "installing ${_pkg_binutils_libqb} so as to build" \
+		            "libqb [${_outfile_qb}]"
+		do_install "${_pkg_binutils_libqb}"
+
+		do_progress "building ${_libqb_descriptor_path} with" \
+		            "${_pkg_binutils_libqb} [${_outfile_qb}]"
+		do_buildsrpm "${_libqb_descriptor_path}" "${_dist}"
+
+		do_progress "installing ${_libqb_descriptor}-based packages" \
+		            "built with ${_pkg_binutils_libqb} [${_outfile_qb}]"
+		do_install "${_libqb_descriptor}"
+		# from now on, we can work fully offline, also to speed
+		# the whole thing up (and not to bother the mirrors)
+		mock_args="${mock_args} --offline"
+
+		for _pkg_binutils_interlib in none "${pkg_binutils_228}" "${pkg_binutils_229}"; do
+
+			case "${_pkg_binutils_interlib}" in
+			none) _outfile="${_outfile_qb}";;
+			${pkg_binutils_228}) _outfile="${_outfile_qb}_il+";;
+			${pkg_binutils_229}) _outfile="${_outfile_qb}_il-";;
+			*) _outfile="${_outfile_qb}_?";;
+			esac
+
+			case "${_pkg_binutils_interlib}" in
+			none)	;;
+			*)
+				do_progress "installing ${_pkg_binutils_interlib}" \
+				            "so as to build interlib [${_outfile}]"
+				do_install "${_pkg_binutils_interlib}"
+
+				do_progress "building interlib with ${_libqb_descriptor_archive}" \
+				            "+ ${_pkg_binutils_interlib} [${_outfile}]" \
+				            "{${_makevars}}"
+				do_compile_interlib "${_libqb_descriptor_archive}" "${_makevars}"
+				;;
+			esac
+
+			for _pkg_binutils_client in "${pkg_binutils_228}" "${pkg_binutils_229}"; do
+
+				_client=client
+				test "${_pkg_binutils_interlib}" = none || _client=interclient
+
+				case "${_pkg_binutils_client}" in
+				${pkg_binutils_228}) _outfile_client="${_outfile}_c+";;
+				${pkg_binutils_229}) _outfile_client="${_outfile}_c-";;
+				*) _outfile_client="${_outfile}_?";;
+				esac
+
+				do_progress "installing ${_pkg_binutils_client}" \
+				            "so as to build ${_client} [${_outfile_client}]"
+				do_install "${_pkg_binutils_client}"
+				do_progress "building ${_client} with ${_libqb_descriptor_archive}" \
+				            "+ ${_pkg_binutils_client} [${_outfile_client}]" \
+				            "{${_makevars}}"
+				do_compile_and_test_client "${_libqb_descriptor_archive}" \
+				                           "${_client}" "${_resultsdir}" \
+				                           "${_outfile_client}" "${_makevars}"
+			done
+		done
+	done
+}
+
+{ test $# -eq 0 || test "$1" = -h || test "$1" = --help; } \
+  && printf '%s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n' \
+            "usage: $0 {[-n{sc,cl,il}]* <libqb.src.rpm> | shell}" \
+            "- use '-nsc' to suppress optional self-check (\"see whole story\")" \
+            "- use '-ncl' to suppress client-side logging" \
+            "- use '-nil' to suppress interlib-side logging" \
+            "- 'make -C ../.. srpm' (or so) can generate the requested input" \
+            "   (in that case, apparently, refer to '../../libqb-X.src.rpm')" \
+            "- _pkgs dir caches (intermediate or not) packages to work with" \
+            "- results stored in '_results/<timestamp>_<input_name>[_<tag>]'" \
+  || do_proceed "$@"
-- 
2.14.2
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin