#
#
# add_file "unix/tester-check-net.c"
# content [bb758c2b16c6a1978a5a96f4ddd204b6feac6e37]
#
# add_file "win32/tester-check-net.c"
# content [939b4453fe11bc0e1883797f0052ca45f760ea1a]
#
# patch "Makefile.am"
# from [f38db1b6891b304f75527eb30853aa570ff15b4d]
# to [4eba20c4f0654b122564fe6845edbc7f5cd55f18]
#
# patch "debian/changelog"
# from [8df684e2d19b17b984d67b3657d756dae8f14159]
# to [89118785c13abb11285cb1315e6c16276f896dec]
#
# patch "lua-testsuite.lua"
# from [41e44b694e1d68e32ba5bf9bca044a11f48f1028]
# to [670f9ca900ae63d2091e68af4561a1870bfc2a6f]
#
# patch "tests/common/netsync.lua"
# from [3e28b68bf122aefa0f55f5d3dfb80338f55bba2b]
# to [3740674f76b3efe676df404047e219b604bc3be5]
#
============================================================
--- unix/tester-check-net.c bb758c2b16c6a1978a5a96f4ddd204b6feac6e37
+++ unix/tester-check-net.c bb758c2b16c6a1978a5a96f4ddd204b6feac6e37
@@ -0,0 +1,283 @@
+/* Copyright (C) 2008 Zack Weinberg
+
+ This program is made available under the GNU GPL version 2.0 or
+ greater. See the accompanying file COPYING for details.
+
+ This program is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. */
+
+/* The test suite runs this program to decide whether or not to include
+ network tests. It determines whether it is possible to create a
+ listening socket on a randomly chosen port on the loopback interface,
+ connect to that socket from another process, and ping-pong a byte.
+
+ Will exit successfully, with no output, if everything works; otherwise,
+ will exit unsuccessfully and produce diagnostics on stderr. */
+
+#include "config.h"
+#if defined HAVE_SOCKET && defined HAVE_NETINET_IN_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+static int synchronizer[2];
+static const char *who;
+static unsigned short port;
+
+static void sigalrm(int unused)
+{
+ fprintf(stderr, "%s: timeout\n", who);
+ exit(1);
+}
+
+static void prep_timeout(const char *w)
+{
+ who = w;
+ signal(SIGALRM, sigalrm);
+ alarm(5);
+}
+
+/* "b_or_c" should be either "bind" or "connect". Conveniently, they have
+ the same signature. */
+static int get_socket(int (*b_or_c)(int, const struct sockaddr *, socklen_t))
+{
+ int sfd;
+
+ /* try IPv4 first */
+ {
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ sfd = socket(PF_INET, SOCK_STREAM, 0);
+ if (sfd >= 0)
+ {
+ if (b_or_c(sfd, (struct sockaddr *)&sin, sizeof sin) == 0)
+ return sfd;
+ close(sfd);
+ }
+ }
+
+ /* if that didn't work, and we have library support for it, try IPv6 too */
+#ifdef AF_INET6
+ {
+ struct sockaddr_in6 sin6;
+ memset(&sin6, 0, sizeof sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(port);
+ sin6.sin6_addr = in6addr_loopback;
+
+ sfd = socket(PF_INET6, SOCK_STREAM, 0);
+ if (sfd >= 0)
+ {
+ if (b_or_c(sfd, (struct sockaddr *)&sin6, sizeof sin6) == 0)
+ return sfd;
+ close(sfd);
+ }
+ }
+#endif
+
+ fprintf(stderr, "socket/connect/bind: %s\n", strerror(errno));
+ return -1;
+}
+
+static int server(void)
+{
+ int sfd, cfd, n;
+ char buf;
+
+ prep_timeout("server");
+
+ sfd = get_socket(bind);
+ if (sfd < 0)
+ return 1;
+
+ if (listen(sfd, 1))
+ {
+ fprintf(stderr, "server: listen: %s\n", strerror(errno));
+ close(sfd);
+ return 1;
+ }
+
+ /* Client process may proceed. */
+ n = write(synchronizer[1], "x", 1);
+ if (n != 1)
+ {
+ fprintf(stderr, "server: semaphore write: %s\n",
+ n == 0 ? "unexpected EOF" : strerror(errno));
+ close(sfd);
+ return 1;
+ }
+
+ cfd = accept(sfd, 0, 0); /* don't care _who_ connects */
+ if (cfd < 0)
+ {
+ fprintf(stderr, "server: accept: %s\n", strerror(errno));
+ close(sfd);
+ return 1;
+ }
+
+ n = read(cfd, &buf, 1);
+ if (n != 1)
+ {
+ fprintf(stderr, "server: socket read: %s\n",
+ n == 0 ? "unexpected EOF" : strerror(errno));
+ close(cfd);
+ close(sfd);
+ return 1;
+ }
+ if (buf != 'x')
+ {
+ fprintf(stderr, "server: socket read: got '%c' exp 'x'\n", buf);
+ close(cfd);
+ close(sfd);
+ return 1;
+ }
+ n = write(cfd, "x", 1);
+ if (n != 1)
+ {
+ fprintf(stderr, "server: socket write: %s\n",
+ n == 0 ? "unexpected EOF" : strerror(errno));
+ close(cfd);
+ close(sfd);
+ return 1;
+ }
+
+ close(cfd);
+ close(sfd);
+ return 0;
+}
+
+static int client(void)
+{
+ int sfd, n;
+ char buf;
+
+ prep_timeout("client");
+
+ /* wait for server setup */
+ n = read(synchronizer[0], &buf, 1);
+ if (n != 1)
+ {
+ fprintf(stderr, "client: semaphore read: %s\n",
+ n == 0 ? "unexpected EOF" : strerror(errno));
+ return 1;
+ }
+
+ sfd = get_socket(connect);
+ if (sfd < 0)
+ return 1;
+
+ n = write(sfd, "x", 1);
+ if (n != 1)
+ {
+ fprintf(stderr, "client: socket write: %s\n",
+ n == 0 ? "unexpected EOF" : strerror(errno));
+ close(sfd);
+ return 1;
+ }
+
+ n = read(sfd, &buf, 1);
+ if (n != 1)
+ {
+ fprintf(stderr, "client: socket read: %s\n",
+ n == 0 ? "unexpected EOF" : strerror(errno));
+ close(sfd);
+ return 1;
+ }
+ if (buf != 'x')
+ {
+ fprintf(stderr, "client: socket read: got '%c' exp 'x'\n", buf);
+ close(sfd);
+ return 1;
+ }
+
+ close(sfd);
+ return 0;
+}
+
+int main(void)
+{
+ pid_t child, p;
+ int status;
+
+ /* Pick a random port in the high half of the range, thus
+ unlikely to be used for anything. */
+ srand(time(0));
+ do
+ {
+ port = rand();
+ }
+ while (port < 32767);
+
+ if (pipe(synchronizer))
+ {
+ fprintf(stderr, "setup: pipe: %s\n", strerror(errno));
+ return 2;
+ }
+
+ child = fork();
+ if (child < 0)
+ {
+ fprintf(stderr, "setup: fork: %s\n", strerror(errno));
+ return 2;
+ }
+
+ if (child == 0)
+ return client();
+
+ if (server())
+ return 1;
+
+ p = wait(&status);
+ if (p < 0)
+ {
+ fprintf(stderr, "teardown: wait: %s\n", strerror(errno));
+ return 2;
+ }
+ if (p != child)
+ {
+ fprintf(stderr, "teardown: unexpected child %d != %d\n", p, child);
+ return 2;
+ }
+ if (!WIFEXITED(status))
+ {
+ fprintf(stderr, "teardown: child crash, status %d\n", status);
+ return 2;
+ }
+
+ return WEXITSTATUS(status);
+}
+
+#else /* no socket, or no netinet/in.h */
+
+int main(void)
+{
+ fprintf(stderr, "socket headers are missing, cannot test networking\n");
+ return 1;
+}
+
+#endif
+
+/*
+ Local Variables:
+ mode: C
+ fill-column: 76
+ c-file-style: "gnu"
+ indent-tabs-mode: nil
+ End:
+ vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:
+ */
============================================================
--- win32/tester-check-net.c 939b4453fe11bc0e1883797f0052ca45f760ea1a
+++ win32/tester-check-net.c 939b4453fe11bc0e1883797f0052ca45f760ea1a
@@ -0,0 +1,6 @@
+/* Stub - needs implementing. See lua-testsuite.lua (very end) for rationale,
+ and unix/tester-check-net.c for behavior to emulate. */
+int main(void)
+{
+ return 0;
+}
============================================================
--- Makefile.am f38db1b6891b304f75527eb30853aa570ff15b4d
+++ Makefile.am 4eba20c4f0654b122564fe6845edbc7f5cd55f18
@@ -454,11 +454,13 @@ if WIN32_PLATFORM
lib3rdparty_a_CPPFLAGS += -DWIN32
lib3rdparty_a_SOURCES += botan/es_capi.cpp botan/es_win32.cpp
tester_SOURCES += win32/tester-plaf.cc
+ check_net_SOURCES = win32/tester-check-net.c
else
libplatform_a_SOURCES += $(UNIX_PLATFORM_SOURCES)
mtn_SOURCES += unix/main.cc
lib3rdparty_a_SOURCES += botan/es_dev.cpp
tester_SOURCES += unix/tester-plaf.cc
+ check_net_SOURCES = unix/tester-check-net.c
endif
if MISSING_INET_PTON
@@ -648,9 +650,9 @@ run_%_tests: Makefile
%_tests.status: run_%_tests %-testsuite.lua tester$(EXEEXT) FORCE
+./run_$*_tests
-unit_tests.status : unit_tester
-lua_tests.status : mtn
-check_PROGRAMS = unit_tester tester
+unit_tests.status : unit_tester$(EXEEXT)
+lua_tests.status : mtn$(EXEEXT) check_net$(EXEEXT)
+check_PROGRAMS = unit_tester tester check_net
# We want the tests re-run even if the .status files already exist.
# .PHONY does not work for that (bad interaction with pattern rules),
============================================================
--- debian/changelog 8df684e2d19b17b984d67b3657d756dae8f14159
+++ debian/changelog 89118785c13abb11285cb1315e6c16276f896dec
@@ -1,5 +1,8 @@ monotone (0.40-2) unstable; urgency=low
monotone (0.40-2) unstable; urgency=low
+ * Automatically skip all tests involving netsync if it is impossible
+ to use TCP on the loopback interface. (Closes: #474280)
+
* Install HTML documentation in /usr/share/doc/monotone/html, not
/usr/share/doc/html. (Closes: #480072)
* Make /usr/share/doc/monotone-server and /usr/share/doc/monotone-doc
@@ -9,7 +12,7 @@ monotone (0.40-2) unstable; urgency=low
* Register monotone manual with doc-base.
* Improve description of monotone-doc package.
- -- Zack Weinberg Sat, 24 May 2008 09:30:07 -0400
+ -- Zack Weinberg Sun, 25 May 2008 00:10:11 -0400
monotone (0.40-1) unstable; urgency=low
============================================================
--- lua-testsuite.lua 41e44b694e1d68e32ba5bf9bca044a11f48f1028
+++ lua-testsuite.lua 670f9ca900ae63d2091e68af4561a1870bfc2a6f
@@ -1,6 +1,7 @@ monotone_path = nil
#!./tester
monotone_path = nil
+no_network_tests = false
function safe_mtn(...)
if monotone_path == nil then
@@ -357,6 +358,36 @@ function prepare_to_run_tests (P)
end
unlogged_remove(d)
+ -- Several tests require the ability to run a network server on
+ -- the loopback interface, and connect to it from another process
+ -- on this computer. Unlike the above, we just skip those tests
+ -- (loudly) if we can't do that. Verifying that this is possible
+ -- requires a helper program.
+
+ local checknet = getpathof("check_net")
+ if checknet ~= nil then
+ writefile_q("in", nil)
+ prepare_redirect("in", "out", "err")
+ local status = execute(checknet)
+ local out = readfile_q("out")
+ local err = readfile_q("err")
+
+ if status == 0 and err == "" and out == "" then
+ logfile:write("check_net: Can use the loopback interface.\n")
+ else
+ logfile:write(string.format("check_net: failed with status %d\n"..
+ "stdout:\n%s\nstderr:\n%s\n",
+ status, out, err))
+ P("warning: network unavailable, skipping network server tests\n")
+ no_network_tests = true
+ end
+ else
+ P("warning: check_net helper is missing, skipping network server tests\n")
+ no_network_tests = true
+ end
+
+ -- Record the full version of monotone under test in the logfile.
+
monotone_path = getpathof("mtn")
if monotone_path == nil then monotone_path = "mtn" end
set_env("mtn", monotone_path)
============================================================
--- tests/common/netsync.lua 3e28b68bf122aefa0f55f5d3dfb80338f55bba2b
+++ tests/common/netsync.lua 3740674f76b3efe676df404047e219b604bc3be5
@@ -1,3 +1,7 @@
+-- Conveniently, all network tests load this file, so this skip_if
+-- suffices to skip all network tests if the network is unavailable
+-- (see lua-testsuite.lua and [platform]/tester-check-net.c).
+skip_if(no_network_tests)
function mtn2(...)
return mtn("--db=test2.db", "--keydir=keys2", unpack(arg))