test: Initial testing framework
Configure with --enable-testtools. BLD_ROOT is now the top build directory. Current test requires ttynvt to be started (by root) like # BLD_ROOT/src/ttynvt -d -E -S localhost:1234 -n ttyNVT99 Device and server name parameters must be as shown above. Run tests like $ make -C BLD_ROOT test # Builds the other programs too $ make -C BLD_ROOT/test # Only running tests $ make -C BLD_ROOT/test V=1 RUN_OPTS="--gtest_filter=Test1.t1"
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# Unit test makefile
|
||||
#
|
||||
.NOTPARALLEL:
|
||||
|
||||
noinst_PROGRAMS = $(GTESTS)
|
||||
|
||||
GTEST_LIBS = -lgtest -lstdc++
|
||||
|
||||
GTESTS = test_misc test_nvttest
|
||||
|
||||
AM_CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter
|
||||
AM_CFLAGS += $(CFLAGS_ASAN)
|
||||
|
||||
AM_CXXFLAGS = $(AM_CFLAGS)
|
||||
|
||||
AM_CPPFLAGS = -I $(top_builddir)
|
||||
AM_CPPFLAGS += -D TOP_SRC_DIR='"$(top_srcdir)"' -D TOP_BLD_DIR='"$(top_builddir)"'
|
||||
AM_CPPFLAGS += -D BUILD_TEST=1
|
||||
|
||||
LIBS += $(GTEST_LIBS)
|
||||
|
||||
TEST_COMMON = test.cpp test.h
|
||||
|
||||
test_misc_SOURCES = $(TEST_COMMON) test_misc.cpp
|
||||
test_misc_LDADD = $(LIBS)
|
||||
|
||||
test_nvttest_SOURCES = $(TEST_COMMON) test_nvttest.cpp
|
||||
test_nvttest_LDADD = $(LIBS)
|
||||
|
||||
TESTS_RUN = $(addprefix run-, $(GTESTS))
|
||||
|
||||
VG_PROG = valgrind --leak-check=full
|
||||
|
||||
all-local: run
|
||||
|
||||
.PHONY: run $(TESTS_RUN)
|
||||
run: $(TESTS_RUN)
|
||||
$(TESTS_RUN): run-%: %
|
||||
# $(TEST_ENV) ./.libs/$* $(RUN_OPTS)
|
||||
$(TEST_ENV) ./$* $(RUN_OPTS)
|
||||
|
||||
TESTS_RUN_VG = $(addprefix run-vg-, $(GTESTS))
|
||||
|
||||
.PHONY: run-vg $(TESTS_RUN_VG)
|
||||
run-vg: $(TESTS_RUN_VG)
|
||||
$(TESTS_RUN_VG): run-vg-%: %
|
||||
# $(TEST_ENV) $(VG_PROG) ./.libs/$* $(RUN_OPTS)
|
||||
$(TEST_ENV) $(VG_PROG) ./$* $(RUN_OPTS)
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* General test stuff
|
||||
*
|
||||
* - The main() function
|
||||
* - Some printing functions
|
||||
*/
|
||||
#include "test.h"
|
||||
|
||||
int debug = 0;
|
||||
|
||||
static bool ttyout = false;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
ttyout = isatty(STDOUT_FILENO);
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
for (argc--, argv++; argc > 0; argc--, argv++)
|
||||
{
|
||||
s = argv[0];
|
||||
if (*s++ != '-')
|
||||
break;
|
||||
again:
|
||||
switch (*s++)
|
||||
{
|
||||
case 'd':
|
||||
debug++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void _pr_text(const char *col, const char *fmt, va_list args)
|
||||
{
|
||||
char fmtx[1024];
|
||||
|
||||
if (ttyout)
|
||||
snprintf(fmtx, sizeof(fmtx), "%s[ ] - %s%s\n",
|
||||
col, fmt, COL_RST);
|
||||
else
|
||||
snprintf(fmtx, sizeof(fmtx), "[ ] - %s\n", fmt);
|
||||
fmt = fmtx;
|
||||
|
||||
vprintf(fmt, args);
|
||||
}
|
||||
|
||||
void pr_text(const char *col, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
_pr_text(col, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void pr_info(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
_pr_text(COL_YEL, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#ifndef TEST_H
|
||||
#define TEST_H 1
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define D(...) do{ if (debug) printf(__VA_ARGS__); }while(0)
|
||||
#define D2(...) do{ if (debug > 1) printf(__VA_ARGS__); }while(0)
|
||||
|
||||
extern int debug;
|
||||
|
||||
#define COL_RST "\x1B[0m"
|
||||
#define COL_RED "\x1B[31m"
|
||||
#define COL_GRN "\x1B[32m"
|
||||
#define COL_YEL "\x1B[33m"
|
||||
#define COL_BLU "\x1B[34m"
|
||||
#define COL_MAG "\x1B[35m"
|
||||
#define COL_CYN "\x1B[36m"
|
||||
#define COL_WHT "\x1B[37m"
|
||||
|
||||
void pr_text(const char *col, const char *fmt, ...);
|
||||
void pr_info(const char *fmt, ...);
|
||||
|
||||
#endif /* TEST_H */
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "test.h"
|
||||
|
||||
TEST(Misc, dummy)
|
||||
{
|
||||
EXPECT_EQ(1, 1);
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#include "test.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define NVT_NAME "ttyNVT99"
|
||||
#define NVT_DEV "/dev/" NVT_NAME
|
||||
|
||||
#define NVT_SRV TOP_BLD_DIR "/nvtsrv/nvtsrv"
|
||||
#define NVT_TEST TOP_BLD_DIR "/nvttest/nvttest"
|
||||
|
||||
#define NVT_OPTS "-D" NVT_NAME
|
||||
|
||||
#define LAUNCH_NVTTEST(...) proc_launch(NVT_TEST, NVT_OPTS, __VA_ARGS__)
|
||||
|
||||
pid_t proc_spawn(char **argv)
|
||||
{
|
||||
pid_t pid;
|
||||
char buf[1024];
|
||||
|
||||
for (int i = 0, len = 0; argv[i]; i++)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, "%s ", argv[i]);
|
||||
pr_info("Launching: %s", buf);
|
||||
|
||||
pid = fork();
|
||||
if (pid > 0)
|
||||
{
|
||||
pr_info("... ok, pid = %d", pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
// Child
|
||||
|
||||
execv(argv[0], argv);
|
||||
|
||||
pr_info("Launch failed: %m");
|
||||
|
||||
EXPECT_EQ(1, 0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void proc_waitfor(const char *name, pid_t pid)
|
||||
{
|
||||
int err, wstatus;
|
||||
|
||||
pr_info("Wait for %s (pid %d) to finish", name, pid);
|
||||
|
||||
wstatus = 0;
|
||||
err = waitpid(pid, &wstatus, 0);
|
||||
if (err > 0)
|
||||
pr_info("... ok, status = %x", wstatus);
|
||||
else
|
||||
pr_info("... error: %m");
|
||||
|
||||
EXPECT_GT(err, 0);
|
||||
EXPECT_EQ(WEXITSTATUS(wstatus), 0);
|
||||
}
|
||||
|
||||
static pid_t proc_launch(const char *prog, ...)
|
||||
{
|
||||
char *argv[16], *arg;
|
||||
int i;
|
||||
pid_t pid;
|
||||
va_list args;
|
||||
|
||||
va_start(args, prog);
|
||||
|
||||
arg = (char *)prog;
|
||||
i = 0;
|
||||
argv[i++] = arg;
|
||||
for (; arg != NULL;)
|
||||
{
|
||||
arg = va_arg(args, char *);
|
||||
|
||||
argv[i++] = arg;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
pid = proc_spawn(argv);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
bool ttynvt_check()
|
||||
{
|
||||
struct stat st;
|
||||
bool ok;
|
||||
|
||||
ok = stat(NVT_DEV, &st) == 0 && S_ISCHR(st.st_mode);
|
||||
if (!ok)
|
||||
{
|
||||
fprintf(stderr, "\n%s"
|
||||
"************************************************************\n"
|
||||
"*** Invalid device file: '%s'\n"
|
||||
"*** Ensure that ttynvt is launched correcly, e.g.:\n"
|
||||
"# ttynvt -d -E -S localhost:1234 -n %s\n"
|
||||
"*** ttynvt must run as root, and the device and server names\n"
|
||||
"*** must be as shown above.\n"
|
||||
"************************************************************\n"
|
||||
"%s\n", COL_CYN, NVT_DEV, NVT_NAME, COL_RST);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Test1, t1)
|
||||
{
|
||||
int err;
|
||||
pid_t pid_srv, pid;
|
||||
|
||||
ASSERT_TRUE(ttynvt_check());
|
||||
|
||||
pid_srv = proc_launch(NVT_SRV, "-de", "localhost:1234", NULL);
|
||||
ASSERT_GT(pid_srv, 0);
|
||||
|
||||
usleep(100000);
|
||||
|
||||
pid = LAUNCH_NVTTEST(NULL);
|
||||
ASSERT_GT(pid, 0);
|
||||
|
||||
proc_waitfor("nvttest", pid);
|
||||
|
||||
pr_info("Terminate nvtsrv");
|
||||
err = kill(pid_srv, SIGTERM);
|
||||
EXPECT_EQ(err, 0);
|
||||
|
||||
proc_waitfor("nvtsrv", pid_srv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Using fixture */
|
||||
|
||||
/**INDENT-OFF**/
|
||||
class Test2:public::testing::Test {
|
||||
pid_t pid_srv;
|
||||
|
||||
protected:
|
||||
Test2() { }
|
||||
virtual ~Test2() { }
|
||||
|
||||
virtual void SetUp() {
|
||||
|
||||
// Ensure ttynvt is running
|
||||
ASSERT_TRUE(ttynvt_check());
|
||||
|
||||
// NB! Quiet nvtsrv
|
||||
pid_srv = proc_launch(NVT_SRV, "-qe", "localhost:1234", NULL);
|
||||
ASSERT_GT(pid_srv, 0);
|
||||
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
int err;
|
||||
|
||||
pr_info("Terminate nvtsrv");
|
||||
err = kill(pid_srv, SIGTERM);
|
||||
EXPECT_EQ(err, 0);
|
||||
|
||||
proc_waitfor("nvtsrv", pid_srv);
|
||||
}
|
||||
};
|
||||
/**INDENT-ON**/
|
||||
|
||||
TEST_F(Test2, t1)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = LAUNCH_NVTTEST(NULL);
|
||||
ASSERT_GT(pid, 0);
|
||||
|
||||
proc_waitfor("nvttest", pid);
|
||||
}
|
||||
|
||||
// Multiple threads
|
||||
TEST_F(Test2, t2)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
// NB! Quiet nvttest
|
||||
pid = LAUNCH_NVTTEST("-t5", "-q", NULL);
|
||||
ASSERT_GT(pid, 0);
|
||||
|
||||
proc_waitfor("nvttest", pid);
|
||||
}
|
||||
|
||||
// Multiple loops
|
||||
TEST_F(Test2, t3)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
// NB! Quiet nvttest
|
||||
pid = LAUNCH_NVTTEST("-n5", "-q", NULL);
|
||||
ASSERT_GT(pid, 0);
|
||||
|
||||
proc_waitfor("nvttest", pid);
|
||||
}
|
||||
|
||||
// Multiple threads and loops
|
||||
TEST_F(Test2, t4)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
// NB! Quiet nvttest
|
||||
pid = LAUNCH_NVTTEST("-n5", "-t5", "-q", NULL);
|
||||
ASSERT_GT(pid, 0);
|
||||
|
||||
proc_waitfor("nvttest", pid);
|
||||
}
|
||||
Reference in New Issue
Block a user