You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by jc...@apache.org on 2017/05/25 21:18:32 UTC

svn commit: r1796202 - in /httpd/httpd/branches/httpdunit: Makefile.in build/httpdunit_gen_cases.pl build/httpdunit_gen_stubs.pl configure.in test/httpdunit.c test/httpdunit.h

Author: jchampion
Date: Thu May 25 21:18:32 2017
New Revision: 1796202

URL: http://svn.apache.org/viewvc?rev=1796202&view=rev
Log:
httpdunit: a Check-based unit test suite

Add a unit test suite based on Check:

    https://libcheck.github.io/check/

The suite depends on the build system to automatically generate the code
stubs that call every test case.

httpdunit is automatically enabled in the build if configure is able to
find Check via pkg-config. At the moment pkg-config is the only official
(non-deprecated) way to build and link against Check with an autoconf
system, since platforms may distribute Check as a static library.

Note that Check is an LGPL'd library, so we can't distribute test
objects and binaries. Building and running the suite remains optional
and is not required to run the server.

Added:
    httpd/httpd/branches/httpdunit/build/httpdunit_gen_cases.pl   (with props)
    httpd/httpd/branches/httpdunit/build/httpdunit_gen_stubs.pl   (with props)
    httpd/httpd/branches/httpdunit/test/httpdunit.c   (with props)
    httpd/httpd/branches/httpdunit/test/httpdunit.h   (with props)
Modified:
    httpd/httpd/branches/httpdunit/Makefile.in
    httpd/httpd/branches/httpdunit/configure.in

Modified: httpd/httpd/branches/httpdunit/Makefile.in
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/httpdunit/Makefile.in?rev=1796202&r1=1796201&r2=1796202&view=diff
==============================================================================
--- httpd/httpd/branches/httpdunit/Makefile.in (original)
+++ httpd/httpd/branches/httpdunit/Makefile.in Thu May 25 21:18:32 2017
@@ -28,7 +28,7 @@ DISTCLEAN_TARGETS  = include/ap_config_a
 	build/pkg/pkginfo build/config_vars.sh bsd_converted
 EXTRACLEAN_TARGETS = configure include/ap_config_auto.h.in generated_lists \
 	httpd.spec
-PHONY_TARGETS := check check-conf check-dirs check-include
+PHONY_TARGETS := check check-conf check-dirs check-include unittest-objdir
 
 include $(top_builddir)/build/rules.mk
 include $(top_srcdir)/build/program.mk
@@ -431,3 +431,39 @@ check: check-include check-dirs check-co
 	    ./t/TEST -clean && \
 	    ./t/TEST -config && \
 	    ./t/TEST
+
+#
+# Unit Test Suite
+#
+
+# Make sure the object subdirectories we use exist in the build directory during
+# VPATH builds.
+unittest-objdir:
+	@mkdir -p test/unit
+
+# Normally I don't like wildcard sources, but for tests, autodiscovery is the
+# way to go.
+testcase_SOURCES := $(patsubst $(top_srcdir)/%,%,$(wildcard $(top_srcdir)/test/unit/*.c))
+testcase_OBJECTS := $(testcase_SOURCES:%.c=%.lo)
+testcase_STUBS   := $(testcase_SOURCES:%.c=%.tests)
+
+# Each testcase depends on the source file as well as the autogenerated .tests
+# stub.
+$(testcase_OBJECTS): %.lo: %.c %.tests | unittest-objdir
+
+$(testcase_STUBS): %.tests: %.c
+	$(top_srcdir)/build/httpdunit_gen_stubs.pl < "$<" > "$@"
+
+test/httpdunit.cases: $(testcase_SOURCES) | unittest-objdir
+	for t in $^; do \
+	    $(top_srcdir)/build/httpdunit_gen_cases.pl < "$$t"; \
+	done > $@
+
+test/httpdunit.lo: test/httpdunit.c test/httpdunit.cases | unittest-objdir
+
+# httpdunit is only added to $(other_targets) if configure detects a working
+# libcheck on the system.
+httpdunit_OBJECTS := test/httpdunit.lo $(testcase_OBJECTS)
+$(httpdunit_OBJECTS): override LTCFLAGS += $(UNITTEST_CFLAGS)
+test/httpdunit: $(httpdunit_OBJECTS) $(PROGRAM_DEPENDENCIES) $(PROGRAM_OBJECTS)
+	$(LINK) $(httpdunit_OBJECTS) $(PROGRAM_OBJECTS) $(UNITTEST_LIBS) $(PROGRAM_LDADD)

Added: httpd/httpd/branches/httpdunit/build/httpdunit_gen_cases.pl
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/httpdunit/build/httpdunit_gen_cases.pl?rev=1796202&view=auto
==============================================================================
--- httpd/httpd/branches/httpdunit/build/httpdunit_gen_cases.pl (added)
+++ httpd/httpd/branches/httpdunit/build/httpdunit_gen_cases.pl Thu May 25 21:18:32 2017
@@ -0,0 +1,23 @@
+#! /usr/bin/env perl
+
+#
+# Generates a list of test cases to be pulled into the httpdunit main test
+# suite.
+#
+# Supply all the test cases' source file contents on stdin; the resulting code
+# will be printed to stdout. Normally you will want to call this twice: once
+# with --declaration to print the function declarations of all the test cases,
+# and once without any options to produce the code that actually adds each test
+# case to the main suite.
+#
+
+use strict;
+use warnings;
+
+while (my $line = <>) {
+    if ($line =~ /^HTTPD_BEGIN_TEST_CASE(?:\w+)?\((\w+)/) {
+        my $name = "$1_test_case";
+        print "TCase *$name(void); ";
+        print "suite_add_tcase(suite, $name());\n";
+    }
+}

Propchange: httpd/httpd/branches/httpdunit/build/httpdunit_gen_cases.pl
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpd/httpd/branches/httpdunit/build/httpdunit_gen_cases.pl
------------------------------------------------------------------------------
    svn:executable = *

Added: httpd/httpd/branches/httpdunit/build/httpdunit_gen_stubs.pl
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/httpdunit/build/httpdunit_gen_stubs.pl?rev=1796202&view=auto
==============================================================================
--- httpd/httpd/branches/httpdunit/build/httpdunit_gen_stubs.pl (added)
+++ httpd/httpd/branches/httpdunit/build/httpdunit_gen_stubs.pl Thu May 25 21:18:32 2017
@@ -0,0 +1,22 @@
+#! /usr/bin/env perl
+
+#
+# Generates a code stub that adds unit tests to a Check test case.
+#
+# Supply the test case's source file contents on stdin; the resulting code will
+# be printed to stdout. This code is designed to be included as part of the
+# boilerplate at the end of each test case.
+#
+
+use strict;
+use warnings;
+
+while (my $line = <>) {
+    # FIXME: this does not correctly handle macro invocations that are split
+    # over multiple lines.
+    if ($line =~ /^HTTPD_START_LOOP_TEST\((\w+),(.*)\)/) {
+        print "tcase_add_loop_test(testcase, $1, 0, ($2));\n";
+    } elsif ($line =~ /^START_TEST\((\w+)\)/) {
+        print "tcase_add_test(testcase, $1);\n"
+    }
+}

Propchange: httpd/httpd/branches/httpdunit/build/httpdunit_gen_stubs.pl
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpd/httpd/branches/httpdunit/build/httpdunit_gen_stubs.pl
------------------------------------------------------------------------------
    svn:executable = *

Modified: httpd/httpd/branches/httpdunit/configure.in
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/httpdunit/configure.in?rev=1796202&r1=1796201&r2=1796202&view=diff
==============================================================================
--- httpd/httpd/branches/httpdunit/configure.in (original)
+++ httpd/httpd/branches/httpdunit/configure.in Thu May 25 21:18:32 2017
@@ -706,6 +706,22 @@ AC_ARG_WITH(valgrind,
     fi ]
 )
 
+dnl Enable the unit test executable if Check is installed.
+dnl TODO: at the moment, only pkg-config discovery is supported.
+AC_MSG_CHECKING([for Check to enable unit tests])
+if test "x$PKGCONFIG" != "x" && `$PKGCONFIG --atleast-version='0.9.12' check`; then
+  UNITTEST_CFLAGS=`$PKGCONFIG --cflags check`
+  UNITTEST_LIBS=`$PKGCONFIG --libs check`
+  other_targets="$other_targets test/httpdunit"
+
+  AC_MSG_RESULT([yes])
+else
+  AC_MSG_RESULT([no])
+fi
+APACHE_SUBST(UNITTEST_CFLAGS)
+APACHE_SUBST(UNITTEST_LIBS)
+
+
 prefix="$orig_prefix"
 APACHE_ENABLE_MODULES
 

Added: httpd/httpd/branches/httpdunit/test/httpdunit.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/httpdunit/test/httpdunit.c?rev=1796202&view=auto
==============================================================================
--- httpd/httpd/branches/httpdunit/test/httpdunit.c (added)
+++ httpd/httpd/branches/httpdunit/test/httpdunit.c Thu May 25 21:18:32 2017
@@ -0,0 +1,53 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "check.h"
+
+#include "apr_general.h"
+
+static Suite *main_test_suite(void)
+{
+    Suite *suite = suite_create("main");
+
+    /* The list of test cases is automatically generated from the test/unit
+     * directory by the build system. */
+#   include "test/httpdunit.cases"
+
+    return suite;
+}
+
+int main(int argc, const char * const argv[])
+{
+    SRunner *runner;
+    int failed;
+
+    /* Initialize APR and create our test runner. */
+    apr_app_initialize(&argc, &argv, NULL);
+    runner = srunner_create(main_test_suite());
+
+    /* Log TAP to stdout. */
+    srunner_set_tap(runner, "-");
+
+    /* Run the tests and collect failures. */
+    srunner_run_all(runner, CK_SILENT /* output only TAP */);
+    failed = srunner_ntests_failed(runner);
+
+    /* Clean up. */
+    srunner_free(runner);
+    apr_terminate();
+
+    return failed ? 1 : 0;
+}

Propchange: httpd/httpd/branches/httpdunit/test/httpdunit.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpd/httpd/branches/httpdunit/test/httpdunit.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/httpdunit/test/httpdunit.h?rev=1796202&view=auto
==============================================================================
--- httpd/httpd/branches/httpdunit/test/httpdunit.h (added)
+++ httpd/httpd/branches/httpdunit/test/httpdunit.h Thu May 25 21:18:32 2017
@@ -0,0 +1,100 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * httpdunit.h: a collection of test helper macros designed to reduce test
+ * boilerplate and help the build system autogenerate test case definitions.
+ *
+ * Here's how the magic works:
+ *
+ * Every test case under test/unit declares test functions using Check's
+ * START_TEST or the HTTPD_START_LOOP_TEST macro. The build system searches each
+ * source file for those macros and generates an appropriate stub, called
+ * test/unit/<filename>.tests, that will add each test function to the test
+ * case. This stub is then pulled in by three lines of boilerplate at the end of
+ * every test case's source file (see the HTTPD_BEGIN_TEST_CASE documentation,
+ * below).
+ *
+ * The build system uses that same three-line boilerplate to determine the names
+ * of all the test cases, and adds them automatically to the main test suite
+ * using a similar generate-stub-and-include process.
+ */
+
+#include "check.h"
+
+/*
+ * Boilerplate Macros
+ */
+
+/**
+ * Declares a test case. The build system uses this macro to generate a stub,
+ * which will automatically pull the new test case into the main suite.
+ *
+ * After beginning a test case, you must #include the autogenerated testcase
+ * stub ("test/unit/<filename>.tests") and then end the test case with
+ * HTTPD_END_TEST_CASE. For example, for a test case called foobar.c:
+ *
+ *    HTTPD_BEGIN_TEST_CASE(foobar)
+ *    #include "test/unit/foobar.tests"
+ *    HTTPD_END_TEST_CASE
+ *
+ * The NAME identifying the test case must be globally unique within the test
+ * suite; if in doubt, just use the filename (minus extension).
+ */
+#define HTTPD_BEGIN_TEST_CASE(NAME) \
+TCase * NAME##_test_case(void); \
+TCase * NAME##_test_case(void) \
+{ \
+    TCase *testcase = tcase_create(#NAME);
+
+/**
+ * Like HTTPD_BEGIN_TEST_CASE, but additionally declares a pair of setup and
+ * teardown functions for the test case. The setup function is run once before
+ * every test function, and the teardown function is run directly after. Keep in
+ * mind that expensive fixtures will heavily impact test runtime.
+ *
+ * Both setup and teardown take no parameters and return void.
+ *
+ * These functions are passed to Check's tcase_add_checked_fixture(). See the
+ * Check documentation for details; the gist is that checked fixures run after
+ * Check forks the test process, and therefore they cannot influence each other
+ * even if something smashes the heap.
+ */
+#define HTTPD_BEGIN_TEST_CASE_WITH_FIXTURE(NAME, SETUP, TEARDOWN) \
+HTTPD_BEGIN_TEST_CASE(NAME) \
+    tcase_add_checked_fixture(testcase, (SETUP), (TEARDOWN));
+
+/**
+ * Bookend for HTTPD_BEGIN_TEST_CASE[_WITH_FIXTURE], which finishes the test
+ * case function.
+ */
+#define HTTPD_END_TEST_CASE \
+    return testcase; \
+}
+
+/*
+ * Test Declaration Macros
+ */
+
+/**
+ * Use this macro instead of Check's START_TEST when you want to run a test
+ * function multiple times. The build system will add the test function to the
+ * test case using Check's tcase_add_loop_test().
+ *
+ * The loop index is available to the test function as the special variable _i.
+ * _i will start at 0 and increment to a maximum of (NUM_ITERATIONS - 1).
+ */
+#define HTTPD_START_LOOP_TEST(NAME, NUM_ITERATIONS) START_TEST(NAME)

Propchange: httpd/httpd/branches/httpdunit/test/httpdunit.h
------------------------------------------------------------------------------
    svn:eol-style = native