ndt-dev - [ndt-dev] [ndt] r1172 committed - Added an end-to-end test and a basic unit testing framework to run it ...
Subject: NDT-DEV email list created
List archive
[ndt-dev] [ndt] r1172 committed - Added an end-to-end test and a basic unit testing framework to run it ...
Chronological Thread
- From:
- To:
- Subject: [ndt-dev] [ndt] r1172 committed - Added an end-to-end test and a basic unit testing framework to run it ...
- Date: Mon, 08 Dec 2014 19:27:39 +0000
Revision: 1172
Author:
Date: Mon Dec 8 19:27:27 2014 UTC
Log: Added an end-to-end test and a basic unit testing framework to run it in. Also added test support to autoconf.
You can now type
$ make check
and tests will be run.
https://code.google.com/p/ndt/source/detail?r=1172
Added:
/trunk/src/unit_testing.c
/trunk/src/unit_testing.h
/trunk/src/web100srv_unit_tests.c
Modified:
/trunk/src/Makefile.am
=======================================
--- /dev/null
+++ /trunk/src/unit_testing.c Mon Dec 8 19:27:27 2014 UTC
@@ -0,0 +1,49 @@
+#include "unit_testing.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/**
+ * The workhorse method of the test framework. Due to this framework's
+ * minimality, the run_test() method must be explicitly called in main() for
+ * each test you want to run. Also, there is no timeout for tests, which means
+ * an infinite loop will hang the testing framework.
+ *
+ * @param *test_name The displayed name of the test to be run
+ * @param *test_func A pointer to the void() test function
+ * */
+int run_test(const char* test_name, const void (*test_func)()) {
+ int test_exit_code;
+ pid_t child_test_pid;
+ fprintf(stderr, "Running test %s...\n", test_name);
+ // Run each child test in its own subprocess to help prevent tests from
+ // interfering with one another.
+ if ((child_test_pid = fork()) == 0) {
+ // Run the test in the child process.
+ (*test_func)();
+ // The child test process didn't crash or exit(), so exit with success!
+ exit(0);
+ } else {
+ // Wait for the child process to exit, hopefully successfully.
+ waitpid(child_test_pid, &test_exit_code, 0);
+ if (WIFEXITED(test_exit_code) && WEXITSTATUS(test_exit_code) == 0) {
+ fprintf(stderr, " ...Success!\n");
+ return 0;
+ } else {
+ if (WIFEXITED(test_exit_code) &&
+ WEXITSTATUS(test_exit_code) == FAILURE_EXIT_CODE) {
+ fprintf(stderr, " ...TEST FAILED.\n");
+ } else {
+ fprintf(stderr, " ...TEST CRASHED (return code=%d, %s).\n",
+ test_exit_code, strerror(test_exit_code));
+ }
+ // Make sure at least one of the bottom 7 bits is set. Some systems only
+ // pay attention to the bottom 7 bits of the process return code.
+ return (test_exit_code & 127) ? test_exit_code : (1 | test_exit_code);
+ }
+ }
+}
=======================================
--- /dev/null
+++ /trunk/src/unit_testing.h Mon Dec 8 19:27:27 2014 UTC
@@ -0,0 +1,58 @@
+/* A minimal unit testing framework. Runs a test, prints debug output, returns
+ * the return value from the test. If non-zero, then the test failed.
+ * */
+
+#ifndef SRC_UNIT_TESTING_H
+#define SRC_UNIT_TESTING_H
+
+#include <stdio.h>
+
+/** We chose exit code 125 as a magic number to mean "test failed". All other
+ * error codes correspond to the test crashing. If the test crashes with error
+ * code 125, then the error message will be wrong. */
+#define FAILURE_EXIT_CODE 125
+
+/**
+ * Asserts a condition and with an asssociated error message and subsequent
+ * arguments to fprintf. You must supply both the condition and the error
+ * message, but subsequent arguments are optional. If you want to assert a
+ * condition and have a nice default error message, use CHECK instead.
+ *
+ * @param COND The condition being asserted. The condition will be avaluated in
+ * a boolean context.
+ * @param ... The message and associated data to be printed out on error. The
+ * first argument (required) is a char* holding the message to be
+ * printed. The char* and all subsequent arguments are passed
+ * directly to fprintf, which allows you to do things like:
+ * ASSERT(the_answer == 42, "Bad the_answer: %d", the_answer);
+ * in order to create nice error messages.
+ * */
+#define ASSERT(COND, ...) \
+ do { \
+ if (!(COND)) { \
+ fprintf(stderr, "Error at line %d in %s: ", __LINE__, __FILE__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ exit(FAILURE_EXIT_CODE); \
+ } \
+ } while (0)
+
+/**
+ * Asserts a condition using the text of the condition as the error message.
+ *
+ * @param COND The condition being asserted.
+ * */
+#define CHECK(COND) ASSERT(COND, #COND)
+
+/**
+ * Unconditionally causes the test to fail. Useful in error-handling code and
+ * for ensuring certain code paths are never taken.
+ *
+ * @param ... The message and arguments for fprintf indicating why the failure
+ * occurred
+ * */
+#define FAIL(...) ASSERT(0, __VA_ARGS__)
+
+int run_test(const char* test_name, const void (*test_func)());
+
+#endif // SRC_UNIT_TESTING_H
=======================================
--- /dev/null
+++ /trunk/src/web100srv_unit_tests.c Mon Dec 8 19:27:27 2014 UTC
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "unit_testing.h"
+
+/** Runs an end-to-end test of the server and client code. */
+void test_e2e() {
+ pid_t server_pid;
+ pid_t client_pid;
+ int client_exit_code;
+ char hostname[1024];
+ fprintf(stderr, "Starting the server\n");
+ if ((server_pid = fork()) == 0) {
+ execl("./web100srv", "./web100srv", "--port=5555", NULL);
+ perror("Server start error");
+ exit(1); // Children can't FAIL
+ }
+ // Wait until the server port (hopefully) becomes available
+ sleep(1);
+ // Find out the hostname. We can't use "localhost" because then the test
+ // won't go through the TCP stack and so web100 won't work.
+ gethostname(hostname, (sizeof(hostname) / sizeof(char)) - 1);
+ fprintf(stderr, "Starting the client, will attach to %s\n", hostname);
+ if ((client_pid = fork()) == 0) {
+ execl("./web100clt", "./web100clt", "--name", hostname, "--port=5555",
+ NULL);
+ perror("Client start error");
+ exit(1); // Children can't FAIL
+ }
+ waitpid(client_pid, &client_exit_code, 0);
+ kill(server_pid, SIGKILL);
+ ASSERT(WIFEXITED(client_exit_code) && WEXITSTATUS(client_exit_code) == 0,
+ "client exit code was %d", WEXITSTATUS(client_exit_code));
+}
+
+/** Runs each test, returns non-zero to the shell if any tests fail. */
+int main() {
+ int success = 0;
+ success |= run_test("end to end test", &test_e2e);
+ return success;
+}
=======================================
--- /trunk/src/Makefile.am Wed Nov 12 10:35:02 2014 UTC
+++ /trunk/src/Makefile.am Mon Dec 8 19:27:27 2014 UTC
@@ -28,6 +28,8 @@
bin_PROGRAMS =
sbin_PROGRAMS = $(ADD_FAKEWWW)
+noinst_PROGRAMS =
+TESTS =
if HAVE_WEB100
bin_PROGRAMS += analyze viewtrace tr-mkmap genplot
@@ -37,6 +39,8 @@
if HAVE_PCAP_H
if HAVE_JANSSON
sbin_PROGRAMS += web100srv
+noinst_PROGRAMS += web100srv_unit_tests
+TESTS += web100srv_unit_tests
endif
endif
endif
@@ -85,6 +89,12 @@
web100srv_CPPFLAGS ='-DBASEDIR="$(ndtdir)"' -DFORCE_WEB100
web100srv_DEPENDENCIES = $(I2UTILLIBDEPS)
+web100srv_unit_tests_SOURCES = web100srv_unit_tests.c unit_testing.c
+web100srv_unit_tests_LDFLAGS = $(NDTLDFLAGS) $(I2UTILLDFLAGS)
+web100srv_unit_tests_LDADD = $(NDTLIBS) $(I2UTILLIBS) $(I2UTILLIBDEPS) -lpthread $(ZLIB) $(JSONLIB)
+web100srv_unit_tests_CPPFLAGS ='-DBASEDIR="$(ndtdir)"' -DFORCE_WEB100
+web100srv_unit_tests_DEPENDENCIES = $(I2UTILLIBDEPS)
+
web10gsrv_SOURCES = web100srv.c web100-util.c web100-pcap.c web100-admin.c runningtest.c \
network.c usage.c utils.c mrange.c logging.c testoptions.c ndtptestconstants.c \
protocol.c test_sfw_srv.c test_meta_srv.c ndt_odbc.c strlutils.c heuristics.c \
- [ndt-dev] [ndt] r1172 committed - Added an end-to-end test and a basic unit testing framework to run it ..., ndt, 12/08/2014
Archive powered by MHonArc 2.6.16.