Including:
- Split each parse function test set out into separate files.
- Add an allocation failure test for each parsing function.
- Add error check test for each parsing function.
Include tests of internal functions, based on the value of the
CARES_SYMBOL_HIDING macro; need to configure the library with
--disable-symbol-hiding to enable these tests.
Currently get error from Travis on this install step, and downgrading one
version appears to fix the problem.
"Could not find any downloads that satisfy the requirement pyOpenSSL>=0.13
(from requests[security])"
Cover Linux & OSX on the container infrastructure, but install
a later G++ to satisfy the tests' need for C++11.
Use a build matrix to include a variety of build variants:
- ASAN
- UBSAN
- LSAN
- Coverage via coveralls.io
test: invoke ASAN and coverage in Travis build
Also shift to use explicit build matrix
test: Use coveralls.io for coverage tracking
test: Add a build with UBSAN
Also expand and re-order the setting of environment variables
for easier modification.
test: Add LSAN build to Travis config
The tests are written in C++11, using the GoogleTest and GoogleMock
frameworks. They have their own independent autoconf setup, so that
users of the library need not have a C++ compiler just to get c-ares
working (however, the test/configure.ac file does assume the use of
a shared top-level m4/ directory). However, this autoconf setup has
only been tested on Linux and OSX so far.
Run with "./arestest", or "./arestest -v" to see extra debug info.
The GoogleTest options for running specific tests are also
available (e.g. "./arestest --gtest_filter=*Live*").
The tests are nowhere near complete yet (currently hitting around
60% coverage as reported by gcov), but they do include examples
of a few different styles of testing:
- There are live tests (ares-test-live.cc), which assume that the
current machine has a valid DNS setup and connection to the
internet; these tests issue queries for real domains but don't
particularly check what gets returned. The tests will fail on
an offline machine.
- There a few mock tests (ares-test-mock.cc) that set up a fake DNS
server and inject its port into the c-ares library configuration.
These tests allow specific response messages to be crafted and
injected, and so are likely to be used for many more tests in
future.
- To make this generation/injection easier, the dns-proto.h file
includes C++ helper classes for building DNS packets.
- Other library entrypoints that don't require network activity
(e.g. ares_parse_*_reply) are tested directly.
- There are few tests of library-internal functions that are not
normally visible to API users (in ares-test-internal.cc).
- A couple of the tests use a helper method of the test fixture to
inject memory allocation failures, using the earlier change to the
library to allow override of malloc/realloc/free.
- There is also an entrypoint to allow Clang's libfuzzer to drive
the packet parsing code in ares_parse_*_reply, together with a
standalone wrapper for it (./aresfuzz) to allow use of afl-fuzz
for further fuzz testing.
Pull in testing macros from the GNU autoconf archive to allow
configure scripts to test for and setup use of a C++11 compiler
(AX_CXX_COMPILE_STDCXX_11) and the pthreads library (AX_PTHREAD).
Note that these macros are not used by the main library autoconf,
just by the tests (which share the same m4/ directory).
Configure with:
./configure --enable-code-coverage
Show coverage output with:
make code-coverage-capture
Built on m4/ax_code_coverage.m4 from the GNU autoconf archive
to provide the macros to check for presence of gcov + lcov;
upstream macro modified to:
- Remove use of $(AM_DEFAULT_VERBOSITY) , as earlier versions of
autoconf (such as the one used by default on Travis) do not have this.
- Rather than automatically defining CODE_COVERAGE_RULES to be a set
of makefile rules that use ifeq/endif (which is GNU make-specific),
instead only define CODE_COVERAGE_RULES if coverages is turned on,
and in that case don't use conditionals in the makefile.
Add user-visible entrypoints ares_{get,set}_servers_ports(3), which
take struct ares_addr_port_node rather than struct ares_addr_node.
This structure includes a UDP and TCP port number; if this is set
to zero, the channel-wide port values are used as before.
Similarly, add a new ares_set_servers_ports_csv(3) entrypoint, which
is analogous to ares_set_servers(3) except it doesn't ignore any
specified port information; instead, any per-server specified port
is used as both the UDP and TCP port for that server.
The internal struct ares_addr is extended to hold the UDP/TCP ports,
stored in network order, with the convention that a value of zero
indicates that the channel-wide UDP/TCP port should be used.
For the internal implementation of ares_dup(3), shift to use the
_ports() version of the get/set functions, so port information is
transferred correctly to the new channel.
Update manpages, and add missing ares_set_servers_csv to the lists
while we're at it
Allow explicit configuration of the channel's sortlist, by
specifying a string in the same format as the equivalent
/etc/resolv.conf option.
This allows library users to perform the same configuration
that is available via /etc/resolv.conf, but without needing
to change that file.
Add a new ares_library_init_mem() initialization function for the
library which allows the library user to specify their own malloc,
realloc & free equivalents for use library-wide.
Store these function pointers in library-wide global variables,
defaulting to libc's malloc(), realloc() and free().
Change all calls to malloc, realloc and free to use the function pointer
instead. Also ensure that ares_strdup() is always available
(even if the local environment includes strdup(3)), and change the
library code to always use it.
Convert calls to calloc() to use ares_malloc() + memset
Add comments for the benefit of the lcov tool, marking
lines that cannot be hit. Typically these are fall-back
protection arms that are already covered by earlier checks,
and so it's not worth taking out the unhittable code (in case
someone changes the code between the two places in future).
If we get an allocation failure on 2nd or later entry in the sortlist, the
code would return ENOMEM but still leave the initial entries allocated.
Ensure that *sortlist is set to NULL whenever ENOMEM is returned.
If the attempt to transfer IPv6 servers from the old to the new channel
fails, the previous code would still return a channel to the user even though
an error return code was generated. This makes it likely that users would
leak the channel, so explicitly clear the channel in this case.
If (say) init_by_options() fails, the subsequent call to
init_by_defaults() was overwriting the return code with
success. Still call init_by_defaults() regardless, but track
its return value separately
If an AF_UNSPEC query gets a valid response to its AAAA query,
but which has no IPv6 addresses in it, then the code chains on to
a A record query. However, the hostent from the AAAA response
was being leaked along the way (because it gets replaced before
the follow-on end_hquery() invocation).
If we get an allocation failure when processing a particular substring in a
TXT record, that failure is silently lost; fix that by propagating errors from
the inner loop to the outer loop.