diff --git a/cli/Makefile b/cli/Makefile index a51fade7b..cad59b381 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -25,3 +25,4 @@ clean: lightning-cli-clean lightning-cli-clean: $(RM) $(LIGHTNING-CLI_LIB_OBJS) $(DAEMON_JSMN_OBJS) +include cli/test/Makefile diff --git a/cli/test/.gitignore b/cli/test/.gitignore new file mode 100644 index 000000000..9e48a0522 --- /dev/null +++ b/cli/test/.gitignore @@ -0,0 +1 @@ +run-large-input diff --git a/cli/test/Makefile b/cli/test/Makefile new file mode 100644 index 000000000..5846cdff6 --- /dev/null +++ b/cli/test/Makefile @@ -0,0 +1,28 @@ +# Note that these actually #include everything they need, except ccan/ and bitcoin/. +# That allows for unit testing of statics, and special effects. +CLI_TEST_SRC := $(wildcard cli/test/run-*.c) +CLI_TEST_OBJS := $(CLI_TEST_SRC:.c=.o) +CLI_TEST_PROGRAMS := $(CLI_TEST_OBJS:.o=) + +ALL_TEST_PROGRAMS += $(CLI_TEST_PROGRAMS) +ALL_OBJS += $(CLI_TEST_OBJS) + +CLI_TEST_COMMON_OBJS := \ + common/configdir.o \ + common/daemon_conn.o \ + common/htlc_state.o \ + common/json.o \ + common/pseudorand.o \ + common/memleak.o \ + common/msg_queue.o \ + common/utils.o \ + common/type_to_string.o \ + common/permute_tx.o + +update-mocks: $(CLI_TEST_SRC:%=update-mocks/%) + +$(CLI_TEST_PROGRAMS): $(CCAN_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(LIBBASE58_OBJS) $(CLI_TEST_COMMON_OBJS) + +$(CLI_TEST_OBJS): $(LIGHTNING_CLI_HEADERS) $(LIGHTNING_CLI_SRC) + +check: $(CLI_TEST_PROGRAMS:%=unittest/%) diff --git a/cli/test/run-large-input.c b/cli/test/run-large-input.c new file mode 100644 index 000000000..a9d81810f --- /dev/null +++ b/cli/test/run-large-input.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include + +int test_main(int argc, char *argv[]); +ssize_t test_read(int fd, void *buf, size_t len); +int test_socket(int domain, int type, int protocol); +int test_connect(int sockfd, const struct sockaddr *addr, + socklen_t addrlen); +int test_getpid(void); +int test_printf(const char *format, ...); + +#define main test_main +#define read test_read +#define socket test_socket +#define connect test_connect +#define getpid test_getpid +#define printf test_printf + + #include "../lightning-cli.c" +#undef main + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for version_and_exit */ +char *version_and_exit(const void *unused UNNEEDED) +{ fprintf(stderr, "version_and_exit called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +int test_socket(int domain, int type, int protocol) +{ + /* We give a real fd, as it writes to it */ + return open("/dev/null", O_WRONLY); +} + +int test_connect(int sockfd, const struct sockaddr *addr, + socklen_t addrlen) +{ + return 0; +} + +int test_getpid(void) +{ + return 9999; +} + +int test_printf(const char *fmt, ...) +{ + return 0; +} + +static char *response; +static size_t response_off, max_read_return; + +ssize_t test_read(int fd, void *buf, size_t len) +{ + if (len > max_read_return) + len = max_read_return; + if (len > strlen(response + response_off)) + len = strlen(response + response_off); + + memcpy(buf, response + response_off, len); + response_off += len; + return len; +} + +/* Simulate a real log file I captured */ +#define NUM_ENTRIES (137772/2) + +#define HEADER "{ \"jsonrpc\": \"2.0\",\n" \ + " \"id\": \"lightning-cli-9999\",\n" \ + " \"result\" : {\n" \ + " \"creation_time\" : \"1515999039.806099043\",\n" \ + " \"bytes_used\" : 10787759,\n" \ + " \"bytes_max\" : 20971520,\n" \ + " \"log\" : [\n" +#define LOG_ENTRY \ + " {\"type\": \"SKIPPED\", \"num_skipped\": 22},\n" \ + " {\"type\": \"DEBUG\", \"time\": \"241693.051558854\", \"source\": \"lightning_gossipd(14581):\", \"log\": \"TRACE: nonlocal_gossip_broadcast_done\"},\n" +#define TAILER "] } }" + +int main(int argc, char *argv[]) +{ + char *fake_argv[] = { argv[0], "--lightning-dir=/tmp/", "test", NULL }; + + + /* sizeof() is an overestimate, but we don't care. */ + response = tal_arr(NULL, char, + sizeof(HEADER) + + sizeof(LOG_ENTRY) * NUM_ENTRIES + + sizeof(TAILER)); + + strcpy(response, HEADER); + response_off = strlen(HEADER); + + /* Append a huge log */ + for (size_t i = 0; i < NUM_ENTRIES; i++) { + memcpy(response + response_off, LOG_ENTRY, sizeof(LOG_ENTRY)-1); + response_off += sizeof(LOG_ENTRY)-1; + } + + memcpy(response + response_off, TAILER, sizeof(TAILER)-1); + response_off += sizeof(TAILER)-1; + response[response_off++] = '\0'; + assert(strlen(response) == response_off - 1); + assert(response_off < tal_len(response)); + + response_off = 0; + max_read_return = -1; + assert(test_main(3, fake_argv) == 0); + tal_free(response); + return 0; +}