Enhance the testsuite to ensure we don't regress with recent changes to stdin/out handling. This adds: - test-single-sh.sh: prove that 'nbdkit -s sh script' is viable - test-stdio.sh: create plugin that checks stdin/out match /dev/null, then run it with -s, --run, -f
Signed-off-by: Eric Blake <[email protected]> --- tests/Makefile.am | 23 ++++++ tests/test-single-sh.sh | 78 +++++++++++++++++ tests/test-stdio.sh | 95 +++++++++++++++++++++ tests/test-stdio-plugin.c | 170 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 366 insertions(+) create mode 100755 tests/test-single-sh.sh create mode 100755 tests/test-stdio.sh create mode 100644 tests/test-stdio-plugin.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 2aa95890..63d47fc9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -189,6 +189,7 @@ EXTRA_DIST = \ test-retry-reopen-fail.sh \ test-retry-zero-flags.sh \ test-ssh.sh \ + test-stdio.sh \ test-swap.sh \ test.tcl \ test-shebang-perl.sh \ @@ -200,6 +201,7 @@ EXTRA_DIST = \ test-sh-extents.sh \ test-single.sh \ test-single-from-file.sh \ + test-single-sh.sh \ test-split-extents.sh \ test-start.sh \ test-random-sock.sh \ @@ -263,6 +265,8 @@ TESTS += \ test-start.sh \ test-single.sh \ test-single-from-file.sh \ + test-single-sh.sh \ + test-stdio.sh \ test-captive.sh \ test-random-sock.sh \ test-tls.sh \ @@ -289,6 +293,25 @@ test_socket_activation_CPPFLAGS = \ $(NULL) test_socket_activation_CFLAGS = $(WARNINGS_CFLAGS) +# check_LTLIBRARIES won't build a shared library (see automake manual). +# So we have to do this and add a dependency. +noinst_LTLIBRARIES += \ + test-stdio-plugin.la \ + $(NULL) +test-stdio.sh: test-stdio-plugin.la + +test_stdio_plugin_la_SOURCES = \ + test-stdio-plugin.c \ + $(top_srcdir)/include/nbdkit-plugin.h \ + $(NULL) +test_stdio_plugin_la_CPPFLAGS = -I$(top_srcdir)/include +test_stdio_plugin_la_CFLAGS = $(WARNINGS_CFLAGS) +# For use of the -rpath option, see: +# https://lists.gnu.org/archive/html/libtool/2007-07/msg00067.html +test_stdio_plugin_la_LDFLAGS = \ + -module -avoid-version -shared $(SHARED_LDFLAGS) -rpath /nowhere \ + $(NULL) + # check_LTLIBRARIES won't build a shared library (see automake manual). # So we have to do this and add a dependency. noinst_LTLIBRARIES += \ diff --git a/tests/test-single-sh.sh b/tests/test-single-sh.sh new file mode 100755 index 00000000..a1586868 --- /dev/null +++ b/tests/test-single-sh.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# nbdkit +# Copyright (C) 2020 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +source ./functions.sh +set -e +set -x + +requires nbdsh --version + +files="single-sh.script single-sh.log" +rm -f $files + +cleanup_fn rm -f $files + +fail=0 +# Inline scripts are incompatible with -s +if nbdkit -s sh - >/dev/null <<EOF +echo "oops: should not have run '$@'" >>single-sh.log +EOF +then + echo "$0: failed to diagnose -s vs. 'sh -'" + fail=1 +fi +if test -f single-sh.log; then + echo "$0: script unexpectedly ran" + cat single-sh.log + fail=1 +fi + +cat >single-sh.script <<\EOF +case $1 in + get_size) echo 1m ;; + pread) dd if=/dev/zero count=$3 iflag=count_bytes ;; + *) exit 2 ;; +esac +EOF +chmod +x single-sh.script + +# The sh plugin sets up pipes to handle stdin/out per each run of the +# script, but this is not incompatible with using -s for the client +nbdsh -c ' +h.connect_command (["nbdkit", "-s", "sh", "single-sh.script"]) +assert h.get_size() == 1024 * 1024 +buf1 = h.pread (512, 0) +buf2 = bytearray (512) +assert buf1 == buf2 +' + +exit $fail diff --git a/tests/test-stdio.sh b/tests/test-stdio.sh new file mode 100755 index 00000000..43913d66 --- /dev/null +++ b/tests/test-stdio.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +# nbdkit +# Copyright (C) 2019-2020 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +source ./functions.sh +set -xe + +requires nbdsh -c 'exit (not h.supports_uri ())' + +plugin=.libs/test-stdio-plugin.so +requires test -f $plugin + +sock1=`mktemp -u` +sock2=`mktemp -u` +files="test-stdio.in test-stdio.out test-stdio.err + test-stdio.pid1 test-stdio.pid2 $sock1 $sock2" +rm -f $files +cleanup_fn rm -f $files + +# Using a seekable file lets us prove that if the plugin consumes less +# than the full input, the next process sees the rest +cat >test-stdio.in <<EOF +string1 +string2 +EOF + +# .dump_plugin using stdout is normal; using stdin is odd, but viable +{ nbdkit --dump-plugin $plugin; printf 'rest='; cat +} < test-stdio.in > test-stdio.out +grep "input=string1" test-stdio.out +grep "rest=string2" test-stdio.out + +# Test with --run. +nbdkit -v $plugin one=1 --run 'printf cmd=; cat' \ + < test-stdio.in > test-stdio.out +cat test-stdio.out +grep "one=string1" test-stdio.out +grep "cmd=string2" test-stdio.out + +# Test with -f; we have to repeat body of start_nbdkit ourselves +echo "string" | nbdkit -P test-stdio.pid1 -v --filter=exitlast \ + -f -U $sock1 $plugin two=2 | tee test-stdio.out & pid=$! +for i in {1..60}; do + if test -s test-stdio.pid1; then + break + fi + sleep 1 +done +if ! test -s test-stdio.pid1; then + echo "$0: PID file $pidfile was not created" + exit 1 +fi +nbdsh -u "nbd+unix:///?socket=$sock1" -c 'buf = h.pread (512, 0)' +wait $pid +grep "two=string" test-stdio.out + +# Test as daemon +echo "string" | start_nbdkit -P test-stdio.pid2 --filter=exitlast \ + -U $sock2 $plugin three=3 | tee test-stdio.out +nbdsh -u "nbd+unix:///?socket=$sock2" -c 'buf = h.pread (512, 0)' +grep "three=string" test-stdio.out + +# Test with -s; here, the plugin produces no output. +nbdsh -c ' +h.connect_command (["nbdkit", "-v", "-s", "'$plugin'", "four=4"]) +buf = h.pread (512, 0) +' diff --git a/tests/test-stdio-plugin.c b/tests/test-stdio-plugin.c new file mode 100644 index 00000000..6af1ba90 --- /dev/null +++ b/tests/test-stdio-plugin.c @@ -0,0 +1,170 @@ +/* nbdkit + * Copyright (C) 2013-2020 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> + +#include <assert.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#define NBDKIT_API_VERSION 2 + +#include <nbdkit-plugin.h> + +static const char *msg = "input"; + +/* Check whether stdin/out match /dev/null */ +static bool +stdio_check (void) +{ + static int dn = -1; + struct stat st1, st2; + + if (dn == -1) { + dn = open ("/dev/null", O_RDONLY); + assert (dn > STDERR_FILENO); + } + if (fstat (dn, &st1) == -1) + assert (false); + + if (fstat (STDIN_FILENO, &st2) == -1) + assert (false); + if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) + return false; + + if (fstat (STDOUT_FILENO, &st2) == -1) + assert (false); + if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) + return false; + + return true; +} + +static void +stdio_dump_plugin (void) +{ + char *buf = NULL; + size_t len = 0; + bool check = stdio_check (); + + assert (check == false); + + /* Reading from stdin during .dump_plugin is unusual, but not forbidden */ + if (getline (&buf, &len, stdin) == -1) + assert (false); + /* The point of .dump_plugin is to extend details sent to stdout */ + printf ("%s=%s\n", msg, buf); + free (buf); +} + +static int +stdio_config (const char *key, const char *value) +{ + bool check = stdio_check (); + assert (check == false); + msg = key; + return 0; +} + +static int +stdio_config_complete (void) +{ + bool check = stdio_check (); + assert (check == false); + if (nbdkit_stdio_safe ()) { + char *buf = NULL; + size_t len = 0; + + /* Reading from stdin during .config_complete is safe except under -s */ + if (getline (&buf, &len, stdin) == -1) + assert (false); + /* Output during .config_complete is unusual, but not forbidden */ + printf ("%s=%s\n", msg, buf); + free (buf); + } + return 0; +} + +static int +stdio_get_ready (void) +{ + bool check = stdio_check (); + assert (check == true); + return 0; +} + +static void * +stdio_open (int readonly) +{ + bool check = stdio_check (); + assert (check == true); + return NBDKIT_HANDLE_NOT_NEEDED; +} + +static int64_t +stdio_get_size (void *handle) +{ + bool check = stdio_check (); + assert (check == true); + return 1024*1024; +} + +#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL + +static int +stdio_pread (void *handle, void *buf, uint32_t count, uint64_t offset, + uint32_t flags) +{ + bool check = stdio_check (); + assert (check == true); + memset (buf, 0, count); + return 0; +} + +static struct nbdkit_plugin plugin = { + .name = "stdio", + .version = PACKAGE_VERSION, + .dump_plugin = stdio_dump_plugin, + .config = stdio_config, + .config_complete = stdio_config_complete, + .get_ready = stdio_get_ready, + .open = stdio_open, + .get_size = stdio_get_size, + .pread = stdio_pread, +}; + +NBDKIT_REGISTER_PLUGIN(plugin) -- 2.26.0 _______________________________________________ Libguestfs mailing list [email protected] https://www.redhat.com/mailman/listinfo/libguestfs
