#include "wvtest.h" #include "uniconfroot.h" #include "unitempgen.h" #include "uniretrygen.h" #include "uniconfdaemon.h" #include "uniconfgen-sanitytest.h" #include "uniclientgen.h" #include "uniinigen.h" #include "wvunixsocket.h" #include "wvfileutils.h" #include "wvfile.h" #include "uniwatch.h" #include "wvstrutils.h" #include "wvtimeutils.h" #include #include class WvDebugUnixConn : public WvUnixConn { WvLog log; WvString socket; public: WvDebugUnixConn(WvString _name, WvStringParm _socket) : WvUnixConn(_socket), log(_name, WvLog::Debug), socket(_socket) { log("Created UNIX connection on %s\n", socket); } ~WvDebugUnixConn() { log("Destroyed UNIX connection on %s\n", socket); } size_t uread(void *buf, size_t count) { size_t result = WvUnixConn::uread(buf, count); if (result > 0) log("<- %s\n", cstr_escape(buf, result)); return result; } size_t uwrite(const void *buf, size_t count) { size_t result = WvUnixConn::uwrite(buf, count); if (result > 0) log("-> %s\n", cstr_escape(buf, result)); return result; } }; static int delta_count; static void delta_callback(const UniConf &, const UniConfKey &) { ++delta_count; } typedef wv::function client_factory_t; // Returns a new UniClientGen, using a non-logging underlying stream. // unix_conn is set to a pointer to the underlying unix stream. static UniClientGen *quiet_client_factory(WvStringParm name, WvStringParm sockname, WvUnixConn *&unix_conn) { return new UniClientGen(unix_conn = new WvUnixConn(sockname)); } // Set the default client_factory to debug_client_factory if you want to see // what goes through the connection. static UniClientGen *create_client_conn(WvString name, WvString sockname, client_factory_t client_factory = quiet_client_factory) { UniClientGen *client_gen = NULL; while (true) { WvUnixConn *unix_conn; client_gen = client_factory(name, sockname, unix_conn); if (!unix_conn || !unix_conn->isok() || !client_gen || !client_gen->isok()) { WVRELEASE(client_gen); wvout->print("Failed to connect, retrying...\n"); wvdelay(100); } else break; } return client_gen; } WVTEST_MAIN("UniClientGen Sanity Test") { signal(SIGPIPE, SIG_IGN); WvString sockname = wvtmpfilename("uniclientgen.t-sock"); UniConfTestDaemon daemon(sockname, "temp:"); UniClientGen *gen = create_client_conn("sanity", sockname); UniConfGenSanityTester::sanity_test(gen, WvString("unix:%s", sockname)); WVRELEASE(gen); } WVTEST_MAIN("deltas") { signal(SIGPIPE, SIG_IGN); UniConfRoot uniconf; WvString sockname = wvtmpfilename("uniclientgen.t-sock"); unlink(sockname); UniConfTestDaemon daemon(sockname, "temp:", UniConfTestDaemon::autoinc_server_cb); UniClientGen *client_gen = create_client_conn("deltas", sockname); uniconf.mountgen(client_gen); int old_delta_count = delta_count = 0; uniconf.add_callback(client_gen, "", delta_callback, false); int i; for (i=0; i<100; ++i) { client_gen->refresh(); wvdelay(1); } WVPASS(delta_count > old_delta_count); } static time_t file_time(WvStringParm filename) { struct stat st; if (stat(filename, &st) == 0) return st.st_mtime; else { wverr->print("stat(%s) failed: %s\n", filename, strerror(errno)); return -1; } } WVTEST_MAIN("commit") { signal(SIGPIPE, SIG_IGN); UniConfRoot uniconf; WvString ini_file("/tmp/wvtest-uniclientgen-commit-%s.ini", getpid()); unlink(ini_file); WvString sockname = wvtmpfilename("uniclientgen.t-sock"); UniConfTestDaemon daemon(sockname, WvString("ini:%s", ini_file)); UniClientGen *client_gen = create_client_conn("commit", sockname); uniconf.mountgen(client_gen); uniconf.setmeint(0); uniconf.commit(); time_t old_file_time = file_time(ini_file); WVPASS(old_file_time != -1); WVPASS(old_file_time <= time(NULL)); // utime the ini file into the past time_t real_old_file_time = old_file_time - 5000; utimbuf buf; buf.actime = real_old_file_time; buf.modtime = real_old_file_time; WVPASSEQ(utime(ini_file, &buf), 0); uniconf.setmeint(1); uniconf.commit(); time_t new_file_time = file_time(ini_file); WVPASS(new_file_time != -1); WVPASS(new_file_time > real_old_file_time); unlink(ini_file); } WVTEST_MAIN("refresh") { signal(SIGPIPE, SIG_IGN); UniConfRoot uniconf; WvString ini_file("/tmp/wvtest-uniclientgen-refresh-%s.ini", getpid()); unlink(ini_file); WvString sockname = wvtmpfilename("uniclientgen.t-sock"); UniConfTestDaemon daemon(sockname, WvString("ini:%s", ini_file)); UniClientGen *client_gen = create_client_conn("refresh", sockname); uniconf.mountgen(client_gen); WVPASS(uniconf.xget("key") != "value"); WvFile ini_fd(ini_file, O_WRONLY | O_APPEND | O_CREAT); ini_fd.print("[]\nkey = value\n"); ini_fd.close(); WVPASS(uniconf.refresh()); WVPASS(uniconf.xget("key") == "value"); unlink(ini_file); } #if 0 // Can't run this test -- it takes at least 60 seconds... WVTEST_MAIN("dead uniconfd") { signal(SIGPIPE, SIG_IGN); UniConfRoot uniconf; WvString sockname = get_sockname(); pid_t child = wvfork(); if (child == 0) { UniConfDaemon daemon(uniconf, false, NULL); daemon.setupunixsocket(sockname); WvIStreamList::globallist.append(&daemon, false, "uniconf daemon"); while (true) { WvIStreamList::globallist.runonce(); } _exit(0); } else { WVPASS(child >= 0); UniClientGen *client_gen; while (true) { WvUnixConn *unix_conn; client_gen = new UniClientGen( unix_conn = new WvUnixConn(sockname)); if (!unix_conn || !unix_conn->isok() || !client_gen || !client_gen->isok()) { WVRELEASE(client_gen); wvout->print("Failed to connect, retrying...\n"); wvdelay(100); } else break; } uniconf.mountgen(client_gen); kill(child, SIGSTOP); uniconf.getme(); WVFAIL(client_gen->isok()); kill(child, 9); pid_t rv; while ((rv = waitpid(child, NULL, 0)) != child) { // in case a signal is in the process of being delivered.. if (rv == -1 && errno != EINTR) break; } WVPASS(rv == child); } } #endif int save_callback_calls; static void save_callback() { ++save_callback_calls; } WVTEST_MAIN("SaveCallback") { signal(SIGPIPE, SIG_IGN); UniConfRoot uniconf; WvString ini_file("/tmp/wvtest-uniclientgen-refresh-%s.ini", getpid()); unlink(ini_file); UniIniGen *ini_gen = new UniIniGen(ini_file, 0600, save_callback); uniconf.mountgen(ini_gen); int items; for (items = 0; items < 5; items++) uniconf["Items"].xsetint(items, items); save_callback_calls = 0; uniconf.commit(); WVPASS(save_callback_calls >= items); unlink(ini_file); } WVTEST_MAIN("timeout") { signal(SIGPIPE, SIG_IGN); WvString sockname = wvtmpfilename("unisubtreegen.t-sock"); unlink(sockname); UniConfTestDaemon daemon(sockname, "temp:"); UniConfRoot uniconf; UniClientGen *client_gen = create_client_conn("timeout", sockname); uniconf.mountgen(client_gen); client_gen->set_timeout(1000); uniconf.getme(); WVPASS(client_gen->isok()); kill(daemon.get_pid(), SIGSTOP); uniconf.getme(); WVPASS(!client_gen->isok()); kill(daemon.get_pid(), SIGCONT); }