Add test_variable_data framework that reuses the snippets

Most of these snippets are likely to have some env var that causes the
data to hold constant, while the data will otherwise be likely to vary
over time.

This framework offers a way to test those snippets, by dropping the
variable and an example value in the test/snippets/FOO.variable
one-line file.

Note that the test/snippets/syscall.c snippet is *not* expected to
vary over time (or to differ when any given variable is set), so we
simply don't add any test/snippets/syscall.variable file to avoid it
being tested in this way.
This commit is contained in:
Daniel Kahn Gillmor
2021-02-25 21:41:25 -05:00
parent a51a38d0ae
commit 0872c6c0c0
7 changed files with 81 additions and 7 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ timetest
test/getrandom_test
test/lib*.so
test/use_lib_*
test/run_*
test/repeat_random
test/getentropy_test
test/syscall_test

View File

@@ -7,6 +7,7 @@ SRC = timetest.c
OBJ = ${SRC:.c=.o}
TESTFUNCS = $(notdir $(basename $(wildcard snippets/*.c)))
EXPECTATIONS= $(notdir $(basename $(wildcard snippets/*.variable)))
all: timetest test
@@ -37,6 +38,14 @@ syscalltest: syscall_test
./syscalltest.sh
## test variables
test_variable_data: test_variable_data.sh $(foreach f,${EXPECTATIONS},run_${f})
./test_variable_data.sh ${EXPECTATIONS}
run_%: _run_test.c snippets/%.c
sed s/FUNC_NAME/$*/g < _run_test.c | ${CC} -o $@ ${CFLAGS} -x c -
## testing when interception points get called in library constructors:
test_library_constructors: test_constructors.sh $(foreach f,${TESTFUNCS},use_lib_${f} lib${f}.so)
@@ -52,7 +61,7 @@ use_lib_%: _use_lib_test.c snippets/%.c lib%.so
## cleanup and metainformation
clean:
@rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TESTFUNCS},use_lib_${f} lib${f}.so)
@rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TESTFUNCS},use_lib_${f} lib${f}.so run_${f})
distclean: clean
@echo

5
test/_run_test.c Normal file
View File

@@ -0,0 +1,5 @@
#include "snippets/include_headers.h"
#define where "direct"
int main() {
#include "snippets/FUNC_NAME.c"
}

View File

@@ -15,10 +15,13 @@ getpid.c for a simple example.
The data sent to stdout should include the const char* "where" value
(which is an indication of which test framework is using the snippet).
And it should ideally be stable when the associated variable
(e.g. FAKETIME, FAKETIME_FAKEPID, or FAKERANDOM_SEED) is set, and
likely to vary otherwise, especially across a delay of a second or
more.
If the output of the snippet is expected to be stable when the
associated variable (e.g. FAKETIME, FAKETIME_FAKEPID, or
FAKERANDOM_SEED) is set, and is likely to vary otherwise, especially
across a delay of a second or more, add a single-line file
FOO.variable that contains the name of the variable separated by a
space and then the value of the variable.
If the snippet needs to additional #include headers, please add them
in include_headers.h. These #includes will be used by every snippet,
@@ -28,5 +31,5 @@ Testing across functions
------------------------
If you want to test something systemically, autogenerate code that
uses each snippet. See test_library_constructors in ../Makefile for
an example.
uses each snippet. See test_variable_data or
test_library_constructors in ../Makefile for an example.

View File

@@ -0,0 +1 @@
FAKETIME_FAKEPID 1

View File

@@ -0,0 +1 @@
FAKERANDOM_SEED 0xDEADBEEFDEADBEEF

54
test/test_variable_data.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
set -e
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
DELAY="${DELAY:-2}"
declare -A firstunset first second delayed delayedunset
err=0
for func in "$@"; do
if ! [ -x "./run_$func" ]; then
printf >&2 '%s does not exist, failing\n' "./run_$func"
exit 1
fi
read varname value < "snippets/$func.variable"
unset $varname
firstunset[$func]="$(env LD_PRELOAD="$FTPL" "./run_$func")"
first[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
second[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
if [ "${first[$func]}" != "${second[$func]}" ]; then
printf >&2 '[%s] Set %s="%s", but got two different outputs:\n - %s\n - %s\n' "$func" "$varname" "$value" "${first[$func]}" "${second[$func]}"
err=$(( $err + 1 ))
fi
if [ "${first[$func]}" == "${firstunset[$func]}" ]; then
printf >&2 '[%s] Same answer when %s="%s" and when unset:\n - set: %s\n - unset: %s\n' "$func" "$varname" "$value" "${first[$func]}" "${firstunset[$func]}"
err=$(( $err + 1 ))
fi
done
printf "Sleeping %d seconds..." "$DELAY"
sleep "$DELAY"
printf 'done\n'
for func in "$@"; do
read varname value < "snippets/$func.variable"
unset $varname
delayed[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
delayedunset[$func]="$(LD_PRELOAD="$FTPL" "./run_$func")"
if [ "${first[$func]}" != "${delayed[$func]}" ]; then
printf >&2 '[%s] Vary across delay of %d seconds (%s="%s"):\n - before: %s\n - after: %s\n' "$func" "$DELAY" "$varname" "$value" "${first[$func]}" "${delayed[$func]}"
err=$(( $err + 1 ))
fi
if [ "${firstunset[$func]}" == "${delayedunset[$func]}" ]; then
printf >&2 '[%s] Same answer when unset across delay of %d seconds:\n - before: %s\n - after: %s\n' "$func" "$DELAY" "${firstunset[$func]}" "${delayedunset[$func]}"
err=$(( $err + 1 ))
fi
done
if [ "$err" -gt 0 ]; then
printf >&2 'Got %d errors, failing\n' "$err"
exit 1
fi
exit 0