diff --git a/Makefile b/Makefile index 98d0484d8..20de5f833 100644 --- a/Makefile +++ b/Makefile @@ -187,33 +187,6 @@ $(CCAN_OBJS) $(CDUMP_OBJS) $(HELPER_OBJS) $(BITCOIN_OBJS) $(TEST_PROGRAMS:=.o): # Except for CCAN, everything depends on bitcoin/ and core headers. $(HELPER_OBJS) $(CORE_OBJS) $(BITCOIN_OBJS) $(TEST_PROGRAMS:=.o): $(BITCOIN_HEADERS) $(CORE_HEADERS) $(CCAN_HEADERS) $(GEN_HEADERS) -daemon-test-%: - daemon/test/scripts/shutdown.sh 2>/dev/null || true - NO_VALGRIND=$(NO_VALGRIND) daemon/test/test.sh --$* - -# These don't work in parallel, so chain the deps -daemon-test-steal: daemon-test-dump-onchain -daemon-test-dump-onchain: daemon-test-timeout-anchor -daemon-test-timeout-anchor: daemon-test-different-fee-rates -daemon-test-different-fee-rates: daemon-test-normal -daemon-test-normal: daemon-test-manual-commit -daemon-test-manual-commit: daemon-test-mutual-close-with-htlcs -daemon-test-mutual-close-with-htlcs: daemon-test-steal\ --reconnect -daemon-test-steal\ --reconnect: daemon-test-dump-onchain\ --reconnect -daemon-test-dump-onchain\ --reconnect: daemon-test-timeout-anchor\ --reconnect -daemon-test-timeout-anchor\ --reconnect: daemon-test-different-fee-rates\ --reconnect -daemon-test-different-fee-rates\ --reconnect: daemon-test-normal\ --reconnect -daemon-test-normal\ --reconnect: daemon-test-manual-commit\ --reconnect -daemon-test-manual-commit\ --reconnect: daemon-test-mutual-close-with-htlcs\ --reconnect -daemon-test-mutual-close-with-htlcs\ --reconnect: daemon-test-steal\ --restart -daemon-test-steal\ --restart: daemon-test-dump-onchain\ --restart -daemon-test-dump-onchain\ --restart: daemon-test-timeout-anchor\ --restart -daemon-test-timeout-anchor\ --restart: daemon-test-different-fee-rates\ --restart -daemon-test-different-fee-rates\ --restart: daemon-test-normal\ --restart -daemon-test-normal\ --restart: daemon-test-mutual-close-with-htlcs\ --restart -daemon-test-mutual-close-with-htlcs\ --restart: daemon-all -daemon-tests: daemon-test-steal - test-onion: test/test_onion test/onion_key set -e; TMPF=/tmp/onion.$$$$; test/test_onion --generate $$(test/onion_key --pub `seq 20`) > $$TMPF; for k in `seq 20`; do test/test_onion --decode $$(test/onion_key --priv $$k) < $$TMPF > $$TMPF.unwrap; mv $$TMPF.unwrap $$TMPF; done; rm -f $$TMPF @@ -234,7 +207,7 @@ doc/protocol-%.svg: test/test_protocol protocol-diagrams: $(patsubst %.script, doc/protocol-%.svg, $(notdir $(wildcard test/commits/*.script))) -check: daemon-tests test-onion test-protocol bitcoin-tests +check: test-onion test-protocol bitcoin-tests include bitcoin/Makefile diff --git a/daemon/Makefile b/daemon/Makefile index 825b08c51..9d487ef06 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -112,3 +112,5 @@ daemon-clean: daemon-maintainer-clean: $(RM) $(DAEMON_GEN_HEADERS) + +include daemon/test/Makefile diff --git a/daemon/test/Makefile b/daemon/test/Makefile new file mode 100644 index 000000000..1f650877d --- /dev/null +++ b/daemon/test/Makefile @@ -0,0 +1,64 @@ +check: daemon-tests + +daemon-test.sh-%: + daemon/test/scripts/shutdown.sh 2>/dev/null || true + NO_VALGRIND=$(NO_VALGRIND) daemon/test/test.sh --$* + +# These don't work in parallel, so chain the deps +daemon-test.sh-steal: daemon-test.sh-dump-onchain +daemon-test.sh-dump-onchain: daemon-test.sh-timeout-anchor +daemon-test.sh-timeout-anchor: daemon-test.sh-different-fee-rates +daemon-test.sh-different-fee-rates: daemon-test.sh-normal +daemon-test.sh-normal: daemon-test.sh-manual-commit +daemon-test.sh-manual-commit: daemon-test.sh-mutual-close-with-htlcs +daemon-test.sh-mutual-close-with-htlcs: daemon-test.sh-steal\ --reconnect +daemon-test.sh-steal\ --reconnect: daemon-test.sh-dump-onchain\ --reconnect +daemon-test.sh-dump-onchain\ --reconnect: daemon-test.sh-timeout-anchor\ --reconnect +daemon-test.sh-timeout-anchor\ --reconnect: daemon-test.sh-different-fee-rates\ --reconnect +daemon-test.sh-different-fee-rates\ --reconnect: daemon-test.sh-normal\ --reconnect +daemon-test.sh-normal\ --reconnect: daemon-test.sh-manual-commit\ --reconnect +daemon-test.sh-manual-commit\ --reconnect: daemon-test.sh-mutual-close-with-htlcs\ --reconnect +daemon-test.sh-mutual-close-with-htlcs\ --reconnect: daemon-test.sh-steal\ --restart +daemon-test.sh-steal\ --restart: daemon-test.sh-dump-onchain\ --restart +daemon-test.sh-dump-onchain\ --restart: daemon-test.sh-timeout-anchor\ --restart +daemon-test.sh-timeout-anchor\ --restart: daemon-test.sh-different-fee-rates\ --restart +daemon-test.sh-different-fee-rates\ --restart: daemon-test.sh-normal\ --restart +daemon-test.sh-normal\ --restart: daemon-test.sh-mutual-close-with-htlcs\ --restart +daemon-test.sh-mutual-close-with-htlcs\ --restart: daemon-all +daemon-all-test.sh: daemon-test.sh-steal + +# Note that these actually #include everything they need, except ccan/ and bitcoin/. +# That allows for unit testing of statics, and special effects. +DAEMON_TEST_SRC := $(wildcard daemon/test/run-*.c) +DAEMON_TEST_OBJS := $(DAEMON_TEST_SRC:.c=.o) +DAEMON_TEST_PROGRAMS := $(DAEMON_TEST_OBJS:.o=) + +update-mocks-daemon/test/%: daemon/test/% + @set -e; trap "rm -f mocktmp.$*.*" EXIT; \ + START=`fgrep -n '/* AUTOGENERATED MOCKS START */' $< | cut -d: -f1`;\ + END=`fgrep -n '/* AUTOGENERATED MOCKS END */' $< | cut -d: -f1`; \ + if [ -n "$$START" ]; then \ + echo $<: ; \ + head -n $$START $< > mocktmp.$*.new; \ + (cat mocktmp.$*.new; tail -n +$$END $<) > mocktmp.$*.test.c; \ + if ! $(CC) $(CFLAGS) mocktmp.$*.test.c -o mocktmp.$*.out $(HELPER_OBJS) $(CCAN_OBJS) $(LDLIBS) 2>mocktmp.$*.err; then \ + daemon/test/scripts/mockup.sh < mocktmp.$*.err >> mocktmp.$*.new; \ + sed -n 's,.*Generated stub for \(.*\) .*,\t\1,p' < mocktmp.$*.new; \ + fi; \ + tail -n +$$END $< >> mocktmp.$*.new; mv mocktmp.$*.new $<; \ + fi + +update-mocks: $(DAEMON_TEST_SRC:%=update-mocks-%) + +$(DAEMON_TEST_PROGRAMS): $(CCAN_OBJS) $(BITCOIN_OBJS) libsecp256k1.a utils.o + +$(DAEMON_TEST_OBJS): $(CCAN_HEADERS) $(DAEMON_HEADERS) $(DAEMON_SRC) + +VALGRIND=valgrind -q --error-exitcode=99 +VALGRIND_TEST_ARGS = --track-origins=yes --leak-check=full --show-reachable=yes + +daemon-unit-tests: $(DAEMON_TEST_PROGRAMS) + set -e; for f in $(DAEMON_TEST_PROGRAMS); do $(VALGRIND) $(VALGRIND_TEST_ARGS) $$f; done + +daemon-tests: daemon-unit-tests daemon-all-test.sh + diff --git a/daemon/test/run-maxfee.c b/daemon/test/run-maxfee.c new file mode 100644 index 000000000..9c7705f51 --- /dev/null +++ b/daemon/test/run-maxfee.c @@ -0,0 +1,45 @@ +#include "daemon/channel.c" +#include "daemon/htlc.c" +#include +#include + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for db_new_htlc */ +bool db_new_htlc(struct peer *peer, const struct htlc *htlc) +{ fprintf(stderr, "db_new_htlc called!\n"); abort(); } +/* Generated stub for db_update_htlc_state */ +bool db_update_htlc_state(struct peer *peer, const struct htlc *htlc, + enum htlc_state oldstate) +{ fprintf(stderr, "db_update_htlc_state called!\n"); abort(); } +/* Generated stub for log_ */ +void log_(struct log *log, enum log_level level, const char *fmt, ...) + +{ fprintf(stderr, "log_ called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +static void test_maxfee(size_t htlcs, u64 funds) +{ + struct channel_state cstate; + uint64_t maxrate; + + cstate.side[LOCAL].pay_msat = funds; + cstate.side[LOCAL].fee_msat = 0; + cstate.num_nondust = htlcs; + + maxrate = approx_max_feerate(&cstate, LOCAL); + assert(fee_by_feerate(tx_bytes(htlcs), maxrate) <= funds); +} + +int main(void) +{ + size_t htlcs, i; + for (htlcs = 0; htlcs < 600; htlcs++) { + for (i = 0; i < 32; i++) { + test_maxfee(htlcs, i); + test_maxfee(htlcs, 1ULL << i); + test_maxfee(htlcs, (1ULL << i) - 1); + test_maxfee(htlcs, (1ULL << i) + 1); + } + } + return 0; +} diff --git a/daemon/test/scripts/mockup.sh b/daemon/test/scripts/mockup.sh new file mode 100755 index 000000000..0e1882a5d --- /dev/null +++ b/daemon/test/scripts/mockup.sh @@ -0,0 +1,39 @@ +#! /bin/sh + +if [ $# -eq 0 ]; then + # With no args, read stdin to scrape compiler output. + set -- $(while read LINE; do + case "$LINE" in + *undefined\ reference\ to*) + LINE=${LINE#*undefined reference to \`} + echo ${LINE%\'*} + ;; + *) + continue + ;; + esac; done | sort -u) +fi + +for SYMBOL; do + WHERE=$(grep -nH "^[a-z0-9_ ]* [*]*$SYMBOL(" daemon/*.h) + if [ x"$WHERE" != x ]; then + STUB='\n{ fprintf(stderr, "'$SYMBOL' called!\\n"); abort(); }' + else + WHERE=$(grep -nH "^extern \(const \)\?struct [a-zA-Z0-9_]* $SYMBOL;$" daemon/*.h) + if [ x"$WHERE" != x ]; then + STUB=';' + else + echo "/* Could not find declaration for $SYMBOL */" + continue + fi + fi + + echo "/* Generated stub for $SYMBOL */" + FILE=${WHERE%%:*} + FILE_AND_LINE=${WHERE%:*} + LINE=${FILE_AND_LINE#*:} + END=$(tail -n +$LINE < $FILE | grep -n ';$'); + NUM=${END%%:*} + + tail -n +$LINE < $FILE | head -n $NUM | sed 's/^extern *//' | sed 's/PRINTF_FMT([^)]*)//' | sed "s/;\$/$STUB/" +done