diff options
Diffstat (limited to 'usr/src/test')
34 files changed, 2749 insertions, 74 deletions
diff --git a/usr/src/test/Readme.smartos b/usr/src/test/Readme.smartos new file mode 100644 index 0000000000..12a430c4d5 --- /dev/null +++ b/usr/src/test/Readme.smartos @@ -0,0 +1,80 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016, Joyent, Inc. +# + +I) Introduction + +The procedure to run the illumos tests under SmartOS is unlike that for +other distributions because of the zone-centric nature of the distribution, +and because there is no built-in package management for the global zone. + +This Readme assumes you will run the tests in the global zone, as root. +Although it is possible to run some of the tests within a non-global zone, as a +user configured within that zone, that approach is not described here. + +Some test suites, such as the ZFS tests, assume there are available disks to +use for the test run. This configuration is not currently available on a +standard SmartOS installation, where all of the disks are already setup in the +"zones" zpool, so these tests are not runnable at this time. The ZFS tests +also are required to run as a non-root user, and that is non-standard for a +SmartOS global zone, where any user created is lost on reboot. + +II) Setup to Run the Tests + +1) The tests currently require python26 to run, so you need to install this in + the global zone. The easiest way to do this is with pkgsrc using the + following procedure: + + a) Get a copy of the following bootstrap tarball onto the test machine: + https://pkgsrc.joyent.com/packages/SmartOS/bootstrap/bootstrap-2014Q4-multiarch.tar.gz + + b) Install the bootstrap tarball: + # gzcat bootstrap-2014Q4-multiarch.tar.gz | (cd /; tar -xpf -) + + c) Install python26: + pkgin in python26 + +2) You need to get the tests from your build machine onto the test machine's + global zone. This can be done in whatever way is easiest for you. Here is + one simple way: + + a) On your build machine, in your fully built smartos-live proto area, + create a tarball of the test directory: + % cd proto/opt + % tar czf ../opt.tgz * + + + b) Copy the tarball from the build machine to the test machine running + SmartOS (the next step assumes you placed the tarball into the /zones + directory). + +3) In the global zone on your test machine, install the tests. + + # cd /opt + # tar xf /zones/opt.tgz + +III) Run the Tests + +Now that setup is complete, you can run the tests using the normal procedure. +For example: + + # /opt/util-tests/bin/utiltest +or + # /opt/os-tests/bin/ostest + +IV) Running New Tests + +During development, if you are creating or updating new tests, you can repeat +steps 2 and 3 as often as necessary to make the new tests available on the test +machine. diff --git a/usr/src/test/libc-tests/runfiles/default.run b/usr/src/test/libc-tests/runfiles/default.run index 5880329fd1..88b46eeba9 100644 --- a/usr/src/test/libc-tests/runfiles/default.run +++ b/usr/src/test/libc-tests/runfiles/default.run @@ -63,6 +63,8 @@ outputdir = /var/tmp/test_results [/opt/libc-tests/tests/call_once.32] [/opt/libc-tests/tests/call_once.64] [/opt/libc-tests/tests/catopen] +[/opt/libc-tests/tests/env-OS-4089.32] +[/opt/libc-tests/tests/env-OS-4089.64] [/opt/libc-tests/tests/env-7076.32] [/opt/libc-tests/tests/env-7076.64] [/opt/libc-tests/tests/endian.32] diff --git a/usr/src/test/libc-tests/tests/Makefile b/usr/src/test/libc-tests/tests/Makefile index a259d28c89..c99d09502d 100644 --- a/usr/src/test/libc-tests/tests/Makefile +++ b/usr/src/test/libc-tests/tests/Makefile @@ -29,6 +29,7 @@ SUBDIRS = \ wctype PROGS = \ + env-OS-4089 \ aligned_alloc \ c11_threads \ c11_tss \ diff --git a/usr/src/test/libc-tests/tests/env-OS-4089.c b/usr/src/test/libc-tests/tests/env-OS-4089.c new file mode 100644 index 0000000000..0f52201c79 --- /dev/null +++ b/usr/src/test/libc-tests/tests/env-OS-4089.c @@ -0,0 +1,73 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +/* + * Regression test for OS-4089 where doing a putenv() call without an '=' sign + * may lead to a segmentation fault when doing a getenv() depending on the + * circumstances of the environment's layout. Verify putenv() mimics + * unsetenv(). + */ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <sys/debug.h> + +int +main(void) +{ + if (putenv("FOO=bar") != 0) { + fprintf(stderr, "failed to put FOO into the environment: %s\n", + strerror(errno)); + return (1); + } + + if (getenv("FOO") == NULL) { + fprintf(stderr, "failed to retrieve FOO from the " + "environment!\n"); + return (1); + } + + VERIFY0(unsetenv("FOO")); + + if (getenv("FOO") != NULL) { + fprintf(stderr, "Somehow retrieved FOO from the " + "environment after unsetenv()!\n"); + return (1); + } + + if (putenv("FOO=bar") != 0) { + fprintf(stderr, "failed to put FOO into the environment: %s\n", + strerror(errno)); + return (1); + } + + if (getenv("FOO") == NULL) { + fprintf(stderr, "failed to retrieve FOO from the " + "environment!\n"); + return (1); + } + + VERIFY0(putenv("FOO")); + + if (getenv("FOO") != NULL) { + fprintf(stderr, "Somehow retrieved FOO from the " + "environment after putenv()!\n"); + return (1); + } + + return (0); +} diff --git a/usr/src/test/libc-tests/tests/random/Makefile b/usr/src/test/libc-tests/tests/random/Makefile index ed480dacb9..c1a1a18e1f 100644 --- a/usr/src/test/libc-tests/tests/random/Makefile +++ b/usr/src/test/libc-tests/tests/random/Makefile @@ -17,7 +17,6 @@ include $(SRC)/Makefile.master ROOTOPTPKG = $(ROOT)/opt/libc-tests TESTDIR = $(ROOTOPTPKG)/tests/random -ROOTBINDIR = $(ROOTOPTPKG)/bin PROGS = arc4random \ arc4random_prefork \ @@ -74,17 +73,12 @@ arc4random_preforksig: arc4random_forksig.c $(POST_PROCESS) chacha: chacha_tv.c - $(COMPILE.c) -DKEYSTREAM_ONLY -I$(SRC)/common/crypto/chacha -o chacha.o -c $(SRC)/common/crypto/chacha/chacha.c + $(COMPILE.c) -DKEYSTREAM_ONLY -I$(SRC)/common/crypto/chacha \ + -o chacha.o -c $(SRC)/common/crypto/chacha/chacha.c $(COMPILE.c) -I$(SRC)/common/crypto/chacha -o chacha_tv.o -c chacha_tv.c $(LINK.c) -o $@ chacha_tv.o chacha.o $(LDLIBS) $(POST_PROCESS) -$(ROOTBINDIR): - $(INS.dir) - -$(ROOTBINDIR)/%: % - $(INS.file) - $(TESTDIR): $(INS.dir) diff --git a/usr/src/test/os-tests/cmd/ostest.ksh b/usr/src/test/os-tests/cmd/ostest.ksh index afa944b613..d30e7fe6eb 100644 --- a/usr/src/test/os-tests/cmd/ostest.ksh +++ b/usr/src/test/os-tests/cmd/ostest.ksh @@ -14,6 +14,7 @@ # # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. +# Copyright 2016, Joyent, Inc. # export OS_TESTS="/opt/os-tests" @@ -28,12 +29,8 @@ function fail function find_runfile { typeset distro= - if [[ -d /opt/delphix && -h /etc/delphix/version ]]; then - distro=delphix - elif [[ 0 -ne $(grep -c OpenIndiana /etc/release 2>/dev/null) ]]; then - distro=openindiana - elif [[ 0 -ne $(grep -c OmniOS /etc/release 2>/dev/null) ]]; then - distro=omnios + if [[ -f $OS_TESTS/runfiles/default.run ]]; then + distro=default fi [[ -n $distro ]] && echo $OS_TESTS/runfiles/$distro.run diff --git a/usr/src/test/os-tests/runfiles/Makefile b/usr/src/test/os-tests/runfiles/Makefile index 619c9b812a..a4346ca2c9 100644 --- a/usr/src/test/os-tests/runfiles/Makefile +++ b/usr/src/test/os-tests/runfiles/Makefile @@ -12,13 +12,12 @@ # # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. +# Copyright 2016, Joyent, Inc. # include $(SRC)/Makefile.master -SRCS = delphix.run \ - omnios.run \ - openindiana.run +SRCS = default.run ROOTOPTPKG = $(ROOT)/opt/os-tests RUNFILES = $(ROOTOPTPKG)/runfiles diff --git a/usr/src/test/os-tests/runfiles/delphix.run b/usr/src/test/os-tests/runfiles/default.run index 4e73ebc8b3..13ac29f437 100644 --- a/usr/src/test/os-tests/runfiles/delphix.run +++ b/usr/src/test/os-tests/runfiles/default.run @@ -26,3 +26,10 @@ user = root [/opt/os-tests/tests/sigqueue] tests = ['sigqueue_queue_size'] + +[/opt/os-tests/tests/tmpfs] +user = root +tests = ['tmpfs_badmount', 'tmpfs_enospc'] + +[/opt/os-tests/tests/file-locking] +tests = ['runtests.32', 'runtests.64'] diff --git a/usr/src/test/os-tests/runfiles/openindiana.run b/usr/src/test/os-tests/runfiles/openindiana.run deleted file mode 100644 index 4e73ebc8b3..0000000000 --- a/usr/src/test/os-tests/runfiles/openindiana.run +++ /dev/null @@ -1,28 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright (c) 2012 by Delphix. All rights reserved. -# - -[DEFAULT] -pre = -verbose = False -quiet = False -timeout = 60 -post = -outputdir = /var/tmp/test_results - -[/opt/os-tests/tests/poll_test] -user = root - -[/opt/os-tests/tests/sigqueue] -tests = ['sigqueue_queue_size'] diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile index cd4104500c..2c65f957fe 100644 --- a/usr/src/test/os-tests/tests/Makefile +++ b/usr/src/test/os-tests/tests/Makefile @@ -13,6 +13,6 @@ # Copyright (c) 2012 by Delphix. All rights reserved. # -SUBDIRS = poll sigqueue spoof-ras +SUBDIRS = poll sigqueue spoof-ras tmpfs file-locking include $(SRC)/test/Makefile.com diff --git a/usr/src/test/os-tests/tests/file-locking/Makefile b/usr/src/test/os-tests/tests/file-locking/Makefile new file mode 100644 index 0000000000..60601b5fee --- /dev/null +++ b/usr/src/test/os-tests/tests/file-locking/Makefile @@ -0,0 +1,77 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Joyent, Inc. +# + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/test/Makefile.com + +UTILS = util.c + +PROGS = \ + runtests \ + acquire-lock + +C99MODE = -xc99=%all + +SRCS = $(PROGS:%=%.c) $(UTILS) +PROGS32 = $(PROGS:%=%.32) +PROGS64 = $(PROGS:%=%.64) + +runtests.32 := LDLIBS += -lgen +runtests.64 := LDLIBS64 += -lgen + +ROOTOPTDIR = $(ROOT)/opt/os-tests/tests/file-locking +ROOTOPTPROGS = $(PROGS32:%=$(ROOTOPTDIR)/%) \ + $(PROGS64:%=$(ROOTOPTDIR)/%) + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean +clobber := TARGET = clobber +lint := TARGET = lint + +.KEEP_STATE: + +install: $(ROOTOPTPROGS) + +all: $(PROGS32) $(PROGS64) + +lint: lint_SRCS + +clean: + -rm $(PROGS32) $(PROGS64) + +$(ROOTOPTPROGS): $(PROGS32) $(PROGS64) $(ROOTOPTDIR) + +$(ROOTOPTDIR): + $(INS.dir) + +$(ROOTOPTDIR)/%: % + $(INS.file) + +$(ROOTOPTDIR)/%: %.ksh + $(INS.rename) + +%.64: %.c + $(LINK64.c) -o $@ $< $(UTILS) $(LDLIBS64) + $(POST_PROCESS) + +%.32: %.c + $(LINK.c) -o $@ $< $(UTILS) $(LDLIBS) + $(POST_PROCESS) + +clobber: + $(RM) $(PROGS32) $(PROGS64) + +FRC: diff --git a/usr/src/test/os-tests/tests/file-locking/acquire-lock.c b/usr/src/test/os-tests/tests/file-locking/acquire-lock.c new file mode 100644 index 0000000000..c66dfdddc2 --- /dev/null +++ b/usr/src/test/os-tests/tests/file-locking/acquire-lock.c @@ -0,0 +1,161 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +/* + * Acquire the specified kind of lock with the specified parameters. After + * acquiring the lock, a byte will be written to stdout. The program will + * then wait for a byte to be written to stdin before exiting. + * + * Usage: <posix|ofd|flock> <shared|exclusive> <path> + */ + +#include "util.h" +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <sys/file.h> +#include <unistd.h> + + +static void acq_fcntl(int, int, int); +static void acq_flock(int fd, int mode); +static void acq_run(int, lock_style_t, boolean_t); + + +static void +acq_fcntl(int fd, int cmd, int mode) +{ + struct flock fl; + int ret, i; + + /* + * Acquire the lock, and then try reacquiring it several times. Once we + * have acquired the lock, trying to acquire it again should succeed, + * and shouldn't upgrade, downgrade or free the lock. + */ + for (i = 0; i < 3; i++) { + flock_reinit(&fl, mode); + flock_log("Acquiring lock (fcntl)...\n"); + ret = fcntl(fd, cmd, &fl); + if (ret == -1) { + err(EXIT_FAILURE, "fcntl failed"); + } + } + + + /* Let the parent know we have the lock and wait */ + flock_log("Waiting (fcntl)...\n"); + flock_alert(1); + flock_block(0); + + /* Now unlock */ + flock_reinit(&fl, F_UNLCK); + flock_log("Releasing lock (fcntl)...\n"); + ret = fcntl(fd, cmd, &fl); + if (ret == -1) { + err(EXIT_FAILURE, "fcntl failed"); + } +} + + +static void +acq_flock(int fd, int mode) +{ + int ret, i; + + /* + * Acquire the lock, and then try reacquiring it several times. Once we + * have acquired the lock, trying to acquire it again should succeed, + * and shouldn't upgrade, downgrade or free the lock. + */ + for (i = 0; i < 3; i++) { + flock_log("Acquiring lock (flock)...\n"); + ret = flock(fd, mode); + if (ret == -1) { + err(EXIT_FAILURE, "flock failed"); + } + } + + /* Wait to be okayed to unlock */ + flock_log("Waiting (flock)...\n"); + flock_alert(1); + flock_block(0); + + /* Release lock */ + flock_log("Releasing lock (flock)...\n"); + ret = flock(fd, LOCK_UN); + if (ret == -1) { + err(EXIT_FAILURE, "flock failed"); + } +} + + +static void +acq_run(int fd, lock_style_t style, boolean_t is_exclusive) +{ + switch (style) { + case LSTYLE_POSIX: + acq_fcntl(fd, F_SETLKW, is_exclusive ? F_WRLCK : F_RDLCK); + break; + case LSTYLE_OFD: + acq_fcntl(fd, F_OFD_SETLKW, is_exclusive ? F_WRLCK : F_RDLCK); + break; + case LSTYLE_FLOCK: + acq_flock(fd, is_exclusive ? LOCK_EX : LOCK_SH); + break; + default: + abort(); + } +} + + +int +main(int argc, char *argv[]) +{ + char *modestr, *path; + lock_style_t style; + boolean_t is_exclusive; + int fd; + + if (argc < 4) { + errx(EXIT_FAILURE, BAD_ARGS_MESSAGE, argc - 1); + } + + modestr = argv[2]; + path = argv[3]; + + style = flock_styleenum(argv[1]); + + if (strcmp(modestr, "shared") == 0) { + is_exclusive = B_FALSE; + } else if (strcmp(modestr, "exclusive") == 0) { + is_exclusive = B_TRUE; + } else { + errx(EXIT_FAILURE, BAD_MODE_MESSAGE); + } + + boolean_t rdonly = style == LSTYLE_FLOCK || !is_exclusive; + fd = open(path, rdonly ? O_RDONLY : O_WRONLY); + if (fd == -1) { + err(EXIT_FAILURE, "Failed to open %s", path); + } + + acq_run(fd, style, is_exclusive); + + return (0); +} diff --git a/usr/src/test/os-tests/tests/file-locking/runtests.c b/usr/src/test/os-tests/tests/file-locking/runtests.c new file mode 100644 index 0000000000..0a1a4d9976 --- /dev/null +++ b/usr/src/test/os-tests/tests/file-locking/runtests.c @@ -0,0 +1,677 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +/* + * Validate various fcntl(2) and flock(3C) operations. + */ + +#include "util.h" +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <signal.h> +#include <stdlib.h> +#include <strings.h> +#include <sys/debug.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> + + +#define LOCKFILE_FMT "/tmp/.lockfile-%s-%ld" +#define LOCKDIR_FMT "/tmp/.lockdir-%s-%ld" + +typedef struct lockinfo { + char *lf_name; + char *lf_path; + int lf_fd; +} lockinfo_t; + + +static void assert_write_locked_by(lockinfo_t *, pid_t); +static void assert_read_locked_by(lockinfo_t *, pid_t); +static void assert_unlocked(lockinfo_t *); +static void assert_all_unlocked(void); + +static int flock_copyfil(lockinfo_t *, lockinfo_t *); +static int flock_mkfil(lockinfo_t *); +static int flock_mkdir(lockinfo_t *); +static void flock_rminfo(lockinfo_t *); + +static void flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl); +static void flock_run(lock_style_t, boolean_t, lockinfo_t *, + pid_t *, int[]); +static int flock_wait(pid_t pid); +static void flock_cleanup_child(pid_t, int []); + +static void flock_test_invalid(lockinfo_t *, int, short, short, + off_t, off_t); +static void flock_test_exclusive(lock_style_t, lock_style_t, + lockinfo_t *, lockinfo_t *, boolean_t); +static void flock_test_shared(lock_style_t, lock_style_t, lockinfo_t *, + lockinfo_t *, boolean_t); +static void flock_test_upgrade_downgrade(void); + +static char *acqprog = NULL; + +static lockinfo_t flock_fileA = { "a", NULL, -1 }; +static lockinfo_t flock_fileB = { "b", NULL, -1 }; +static lockinfo_t flock_dirA = { "a", NULL, -1 }; +static lockinfo_t flock_dirB = { "b", NULL, -1 }; + + +static short cmds[8] = { + F_SETLK, F_SETLKW, F_GETLK, + F_OFD_SETLK, F_OFD_SETLKW, F_OFD_GETLK, + F_FLOCK, F_FLOCKW +}; + + +static void +flock_kill(pid_t pid) +{ + while (kill(pid, SIGKILL) == -1) { + if (errno == EINTR) + continue; + + err(EXIT_FAILURE, "kill failed"); + } +} + + +static void +flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl) +{ + if (fcntl(lf->lf_fd, cmd, fl) == -1) { + err(EXIT_FAILURE, "fcntl failed"); + } +} + + +static void +assert_write_locked_by(lockinfo_t *lf, pid_t pid) +{ + struct flock fl; + + flock_reinit(&fl, F_WRLCK); + flock_fcntl(lf, F_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); + + flock_reinit(&fl, F_WRLCK); + flock_fcntl(lf, F_OFD_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); + + flock_reinit(&fl, F_RDLCK); + flock_fcntl(lf, F_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); + + flock_reinit(&fl, F_RDLCK); + flock_fcntl(lf, F_OFD_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); +} + + +static void +assert_read_locked_by(lockinfo_t *lf, pid_t pid) +{ + struct flock fl; + + flock_reinit(&fl, F_WRLCK); + flock_fcntl(lf, F_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); + + flock_reinit(&fl, F_WRLCK); + flock_fcntl(lf, F_OFD_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t); + + flock_reinit(&fl, F_RDLCK); + flock_fcntl(lf, F_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); + + flock_reinit(&fl, F_RDLCK); + flock_fcntl(lf, F_OFD_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); +} + +static void +assert_unlocked(lockinfo_t *lf) +{ + struct flock fl; + + flock_reinit(&fl, F_WRLCK); + flock_fcntl(lf, F_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); + + flock_reinit(&fl, F_WRLCK); + flock_fcntl(lf, F_OFD_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); + + flock_reinit(&fl, F_RDLCK); + flock_fcntl(lf, F_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); + + flock_reinit(&fl, F_RDLCK); + flock_fcntl(lf, F_OFD_GETLK, &fl); + VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short); + VERIFY3_IMPL(fl.l_sysid, ==, 0, int); + VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t); +} + + +static void +assert_all_unlocked(void) +{ + assert_unlocked(&flock_fileA); + assert_unlocked(&flock_fileB); + assert_unlocked(&flock_dirA); + assert_unlocked(&flock_dirB); +} + + +static int +flock_copyfil(lockinfo_t *src, lockinfo_t *dst) +{ + dst->lf_name = NULL; + dst->lf_path = NULL; + if ((dst->lf_fd = open(src->lf_path, O_RDWR)) == -1) { + warn("Failed to open %s", src->lf_path); + return (-1); + } + + return (0); +} + + +static int +flock_mkfil(lockinfo_t *lf) +{ + if (asprintf(&lf->lf_path, LOCKFILE_FMT, lf->lf_name, getpid()) < 0) { + warnx("Failed to generate lockfile name"); + return (-1); + } + + if ((lf->lf_fd = open(lf->lf_path, O_RDWR|O_CREAT, 0600)) == -1) { + warn("Failed to open %s", lf->lf_path); + return (-1); + } + + return (0); +} + + +static int +flock_mkdir(lockinfo_t *lf) +{ + if (asprintf(&lf->lf_path, LOCKDIR_FMT, lf->lf_name, getpid()) < 0) { + warnx("Failed to generate lockfile name"); + return (-1); + } + + if (mkdir(lf->lf_path, 0700) == -1) { + warn("Failed to make %s", lf->lf_path); + return (-1); + } + + if ((lf->lf_fd = open(lf->lf_path, O_RDONLY)) == -1) { + warn("Failed to open %s", lf->lf_path); + return (-1); + } + + return (0); +} + + +static void +flock_rminfo(lockinfo_t *lf) +{ + if (lf->lf_fd != -1) { + (void) close(lf->lf_fd); + } + if (lf->lf_path != NULL) { + (void) unlink(lf->lf_path); + free(lf->lf_path); + } +} + + +static void +flock_run(lock_style_t style, boolean_t is_exclusive, lockinfo_t *lf, + pid_t *pid, int fds[]) +{ + char *stylestr = flock_stylestr(style); + char *modestr = is_exclusive ? "exclusive" : "shared"; + char *argv[5] = { acqprog, stylestr, modestr, lf->lf_path, NULL }; + int ret = pipe(fds); + if (ret == -1) { + err(EXIT_FAILURE, "pipe failed"); + } + + *pid = fork(); + if (*pid == (pid_t)-1) { + err(EXIT_FAILURE, "fork failed"); + } else if (*pid == (pid_t)0) { + /* Set up pipe for communicating with child */ + ret = dup2(fds[1], 0); + if (ret == -1) { + err(EXIT_FAILURE, "dup2 failed"); + } + ret = dup2(fds[1], 1); + if (ret == -1) { + err(EXIT_FAILURE, "dup2 failed"); + } + closefrom(3); + + (void) execv(acqprog, argv); + err(EXIT_FAILURE, "Failed to execute %s", acqprog); + } +} + + +static int +flock_wait(pid_t pid) +{ + int childstat = 0; + + while (waitpid(pid, &childstat, 0) == -1) { + if (errno == EINTR) + continue; + + err(EXIT_FAILURE, "Failed to wait on child"); + } + + if (WIFEXITED(childstat)) { + return (WEXITSTATUS(childstat)); + } else if (WIFSIGNALED(childstat)) { + return (1); + } else { + abort(); + return (1); + } +} + + +static void +flock_cleanup_child(pid_t pid, int fds[]) +{ + (void) flock_wait(pid); + (void) close(fds[0]); + (void) close(fds[1]); +} + + +static void +flock_test_upgrade_downgrade(void) +{ + lockinfo_t afd1, afd2, afd3; + pid_t pid; + int fds[2]; + + VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0); + VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0); + VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0); + + flock_log("Acquiring shared locks 1, 2 and 3..."); + VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0); + VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0); + VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0); + assert_read_locked_by(&flock_fileA, -1); + flock_log(" ok\n"); + + flock_log("Upgrading lock 3 should fail w/ EWOULDBLOCK..."); + VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1); + VERIFY3U(errno, ==, EWOULDBLOCK); + assert_read_locked_by(&flock_fileA, -1); + flock_log(" ok\n"); + + flock_log("Upgrading 3 should succeed after releasing locks 1 & 2..."); + VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0); + VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0); + VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); + assert_write_locked_by(&flock_fileA, -1); + flock_log(" ok\n"); + + + flock_log("Starting up child, then downgrading lock 3 to shared..."); + flock_run(LSTYLE_FLOCK, B_FALSE, &flock_fileA, &pid, fds); + VERIFY3_IMPL(flock_nodata(fds[0]), ==, B_TRUE, boolean_t); + VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0); + flock_block(fds[0]); + assert_read_locked_by(&flock_fileA, -1); + flock_log(" ok\n"); + + flock_log("Releasing child and upgrading..."); + flock_alert(fds[0]); + flock_cleanup_child(pid, fds); + assert_read_locked_by(&flock_fileA, -1); + VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); + assert_write_locked_by(&flock_fileA, -1); + flock_log(" ok\n"); + + flock_log("Releasing lock 3..."); + VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0); + flock_rminfo(&afd1); + flock_rminfo(&afd2); + flock_rminfo(&afd3); + assert_all_unlocked(); + flock_log(" ok\n"); +} + + +static void +flock_test_invalid(lockinfo_t *lf, int cmd, short l_type, short l_whence, + off_t l_start, off_t l_len) +{ + struct flock fl = { + .l_type = l_type, + .l_whence = l_whence, + .l_start = l_start, + .l_len = l_len + }; + + flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...", + flock_cmdname(cmd), l_type, l_whence, l_start, l_len); + VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1); + VERIFY3U(errno, ==, EINVAL); + flock_log(" ok\n"); +} + + +static void +flock_test_exclusive(lock_style_t styleA, lock_style_t styleB, + lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn) +{ + pid_t pidA, pidB; + int fdsA[2], fdsB[2]; + + flock_log("Running %s + %s tests (%s)...", + flock_stylename(styleA), flock_stylename(styleB), + kill_firstborn ? "kill child" : "child exits"); + + /* Create child, and wait for it to acquire the lock */ + flock_run(styleA, B_TRUE, lock1, &pidA, fdsA); + flock_block(fdsA[0]); + + /* Create second child, which shouldn't acquire & signal */ + flock_run(styleB, B_TRUE, lock1, &pidB, fdsB); + VERIFY3_IMPL(flock_nodata(fdsB[0]), ==, B_TRUE, boolean_t); + + /* lock1 is blocked for reading and writing */ + assert_write_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1); + assert_unlocked(lock2); + + /* Tell pidA to exit */ + if (kill_firstborn) { + flock_kill(pidA); + } else { + flock_alert(fdsA[0]); + } + flock_cleanup_child(pidA, fdsA); + + /* Wait for pidB to signal us */ + flock_block(fdsB[0]); + + /* lock1 is blocked for reading and writing */ + assert_write_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1); + assert_unlocked(lock2); + + /* Tell pidB to exit */ + flock_alert(fdsB[0]); + + flock_cleanup_child(pidB, fdsB); + + /* + * Tests after child has released lock + */ + assert_all_unlocked(); + + flock_log(" ok\n"); +} + + +static void +flock_test_shared(lock_style_t styleA, lock_style_t styleB, + lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn) +{ + pid_t pidA, pidB; + int fdsA[2], fdsB[2]; + + flock_log("Running %s + %s tests (%s)...", + flock_stylename(styleA), flock_stylename(styleB), + kill_firstborn ? "kill child" : "child exits"); + + /* Create children, and wait for it to acquire the lock */ + flock_run(styleB, B_FALSE, lock1, &pidB, fdsB); + flock_block(fdsB[0]); + flock_run(styleA, B_FALSE, lock1, &pidA, fdsA); + flock_block(fdsA[0]); + + /* testfileA is only blocked for writing */ + assert_read_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1); + assert_unlocked(lock2); + + /* Tell pidA to exit */ + if (kill_firstborn) { + flock_kill(pidA); + } else { + flock_alert(fdsA[0]); + } + flock_cleanup_child(pidA, fdsA); + + /* testfileA is still blocked for writing by pidB */ + assert_read_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1); + assert_unlocked(lock2); + + /* Tell pidB to exit */ + flock_alert(fdsB[0]); + flock_cleanup_child(pidB, fdsB); + + assert_all_unlocked(); + + flock_log(" ok\n"); +} + + +static void +flock_test_ofd_sameproc(void) +{ + lockinfo_t afd1, afd2, afd3; + + VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0); + VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0); + VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0); + + flock_log("Acquiring first two shared locks..."); + VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0); + VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0); + assert_read_locked_by(&flock_fileA, -1); + flock_log(" ok\n"); + + flock_log("Acquiring an exclusive lock should fail w/ EWOULDBLOCK..."); + VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1); + VERIFY3U(errno, ==, EWOULDBLOCK); + flock_log(" ok\n"); + + flock_log("Releasing to acquire an exclusive lock..."); + VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0); + VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0); + flock_log(" ok\n"); + + flock_log("Acquiring an exclusive lock..."); + VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); + assert_write_locked_by(&flock_fileA, -1); + flock_log(" ok\n"); + + flock_log("Acquiring a shared lock should fail w/ EWOULDBLOCK..."); + VERIFY3S(flock(afd1.lf_fd, LOCK_EX|LOCK_NB), ==, -1); + VERIFY3U(errno, ==, EWOULDBLOCK); + VERIFY3S(flock(afd2.lf_fd, LOCK_EX|LOCK_NB), ==, -1); + VERIFY3U(errno, ==, EWOULDBLOCK); + flock_log(" ok\n"); + + flock_log("Releasing exclusive lock..."); + VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0); + assert_all_unlocked(); + flock_log(" ok\n"); + + flock_rminfo(&afd1); + flock_rminfo(&afd2); + flock_rminfo(&afd3); +} + + +static void +flock_runtests(void) +{ + lock_style_t first, second; + int i; + + flock_log("# Exclusive lock tests\n"); + for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) { + for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) { + flock_test_exclusive(first, second, + &flock_fileA, &flock_fileB, B_TRUE); + flock_test_exclusive(first, second, + &flock_fileA, &flock_fileB, B_FALSE); + } + } + + flock_log("# Shared lock tests\n"); + for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) { + for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) { + flock_test_shared(first, second, + &flock_fileA, &flock_fileB, B_TRUE); + flock_test_shared(first, second, + &flock_fileA, &flock_fileB, B_FALSE); + } + } + + flock_log("# flock(3C) directory lock tests\n"); + flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK, + &flock_dirA, &flock_dirB, B_TRUE); + flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK, + &flock_dirA, &flock_dirB, B_FALSE); + flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK, + &flock_dirA, &flock_dirB, B_TRUE); + flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK, + &flock_dirA, &flock_dirB, B_FALSE); + + + flock_log("# Invalid fcntl(2) parameters tests\n"); + for (i = 0; i < sizeof (cmds) / sizeof (short); i++) { + flock_test_invalid(&flock_fileA, cmds[i], 200, 0, 0, 0); + flock_test_invalid(&flock_fileA, cmds[i], -1, 0, 0, 0); + } + for (i = 3; i < sizeof (cmds) / sizeof (short); i++) { + flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 1, 0, 0); + flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 1, 0); + flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 0, 1); + } + + flock_log("# Testing that multiple OFD locks work in a process\n"); + flock_test_ofd_sameproc(); + + flock_log("# Testing flock(3C) upgrade/downgrade tests\n"); + flock_test_upgrade_downgrade(); +} + + +int +main(int argc, char *argv[]) +{ + char *basestr, *suffix, *dirstr, *dirpath; + pid_t testrunner; + int exval; + + LOG = B_TRUE; + + if (argc < 1) { + errx(EXIT_FAILURE, "Can't find program name!"); + } + + dirstr = strdup(argv[0]); + dirpath = dirname(dirstr); + basestr = strdup(argv[0]); + suffix = basename(basestr); + + while (*suffix != '.' && *suffix != '\0') { + suffix += 1; + } + + if (asprintf(&acqprog, "%s/acquire-lock%s", dirpath, suffix) < 0) { + errx(EXIT_FAILURE, + "Can't generate lock acquisition program name!"); + } + + if (access(acqprog, X_OK) != 0) { + err(EXIT_FAILURE, + "Can't run lock acquisition program %s", acqprog); + } + + /* Create several lockfiles for testing */ + if (flock_mkfil(&flock_fileA) != 0 || + flock_mkfil(&flock_fileB) != 0 || + flock_mkdir(&flock_dirA) != 0 || + flock_mkdir(&flock_dirB) != 0) { + exval = 1; + goto cleanup; + } + + /* + * We run the tests in a child process so that when tests fail + * we can still clean up our temporary files. + */ + testrunner = fork(); + if (testrunner == (pid_t)-1) { + err(EXIT_FAILURE, "Unable to fork to run tests"); + } else if (testrunner == (pid_t)0) { + flock_runtests(); + return (0); + } + + exval = flock_wait(testrunner); + +cleanup: + free(basestr); + free(dirstr); + flock_rminfo(&flock_fileA); + flock_rminfo(&flock_fileB); + flock_rminfo(&flock_dirA); + flock_rminfo(&flock_dirB); + return (exval); +} diff --git a/usr/src/test/os-tests/tests/file-locking/util.c b/usr/src/test/os-tests/tests/file-locking/util.c new file mode 100644 index 0000000000..ad171840ae --- /dev/null +++ b/usr/src/test/os-tests/tests/file-locking/util.c @@ -0,0 +1,175 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +/* + * Utility functions for use in both acquire-lock and runtests. + */ + +#include "util.h" +#include <err.h> +#include <errno.h> +#include <poll.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <unistd.h> + + +boolean_t LOG = B_FALSE; + + +void +flock_log(const char *format, ...) +{ + va_list ap; + if (!LOG) { + return; + } + + va_start(ap, format); + (void) vfprintf(stderr, format, ap); + va_end(ap); +} + + +boolean_t +flock_nodata(int fd) +{ + struct pollfd pfd = { fd, POLLIN, 0 }; + int ret = poll(&pfd, 1, 1000); + + if (ret == -1) { + err(EXIT_FAILURE, "poll failed"); + } + + return (ret == 0); +} + + +void +flock_block(int fd) +{ + char buf[1]; + int ret = 0; + while (ret < 1) { + ret = read(fd, buf, 1); + if (ret == -1) { + if (errno == EINTR) + continue; + err(EXIT_FAILURE, "read failed"); + } + } +} + + +void +flock_alert(int fd) +{ + int ret = 0; + while (ret < 1) { + ret = write(fd, "1", 1); + if (ret == -1) { + if (errno == EINTR) + continue; + err(EXIT_FAILURE, "write failed"); + } + } +} + + +lock_style_t +flock_styleenum(char *stylestr) +{ + if (strcmp(stylestr, "posix") == 0) { + return (LSTYLE_POSIX); + } else if (strcmp(stylestr, "ofd") == 0) { + return (LSTYLE_OFD); + } else if (strcmp(stylestr, "flock") == 0) { + return (LSTYLE_FLOCK); + } else { + errx(EXIT_FAILURE, BAD_LOCK_MESSAGE); + return (LSTYLE_LAST); + } +} + + +char * +flock_stylestr(lock_style_t style) +{ + switch (style) { + case LSTYLE_POSIX: + return ("posix"); + case LSTYLE_OFD: + return ("ofd"); + case LSTYLE_FLOCK: + return ("flock"); + default: + abort(); + return ("<unreachable>"); + } +} + + +char * +flock_stylename(lock_style_t style) +{ + switch (style) { + case LSTYLE_POSIX: + return ("fcntl(2) POSIX"); + case LSTYLE_OFD: + return ("fcntl(2) OFD"); + case LSTYLE_FLOCK: + return ("flock(3C)"); + default: + abort(); + return ("<unreachable>"); + } +} + + +void +flock_reinit(struct flock *flp, int ltype) +{ + bzero(flp, sizeof (*flp)); + flp->l_type = ltype; +} + + +char * +flock_cmdname(int cmd) +{ + switch (cmd) { + case F_SETLK: + return ("F_SETLK"); + case F_OFD_SETLK: + return ("F_OFD_SETLK"); + case F_SETLKW: + return ("F_SETLKW"); + case F_OFD_SETLKW: + return ("F_OFD_SETLKW"); + case F_GETLK: + return ("F_GETLK"); + case F_OFD_GETLK: + return ("F_OFD_GETLK"); + case F_FLOCK: + return ("F_FLOCK"); + case F_FLOCKW: + return ("F_FLOCKW"); + default: + abort(); + return ("<unreachable>"); + } +} diff --git a/usr/src/test/os-tests/tests/file-locking/util.h b/usr/src/test/os-tests/tests/file-locking/util.h new file mode 100644 index 0000000000..b6d2b57d8a --- /dev/null +++ b/usr/src/test/os-tests/tests/file-locking/util.h @@ -0,0 +1,49 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +#ifndef FLOCK_TEST_UTIL_H +#define FLOCK_TEST_UTIL_H + +#include <fcntl.h> +#include <sys/types.h> + +#define BAD_ARGS_MESSAGE "Expected to receive 3 arguments, but found %d." +#define BAD_MODE_MESSAGE "Lock mode must be one of " \ + "\"shared\" or \"exclusive\"" +#define BAD_LOCK_MESSAGE "Lock style must be one of " \ + "\"posix\", \"ofd\", or \"exclusive\"" + +typedef enum lock_style { + LSTYLE_POSIX, + LSTYLE_OFD, + LSTYLE_FLOCK, + LSTYLE_LAST +} lock_style_t; + +extern boolean_t LOG; + +extern boolean_t flock_nodata(int); + +extern void flock_block(int); +extern void flock_alert(int); +extern void flock_log(const char *, ...); +extern void flock_reinit(struct flock *, int); + +extern char *flock_cmdname(int); +extern char *flock_stylename(lock_style_t); +extern char *flock_stylestr(lock_style_t); +extern lock_style_t flock_styleenum(char *); + +#endif /* FLOCK_TEST_UTIL_H */ diff --git a/usr/src/test/os-tests/tests/tmpfs/Makefile b/usr/src/test/os-tests/tests/tmpfs/Makefile new file mode 100644 index 0000000000..d6515b38fa --- /dev/null +++ b/usr/src/test/os-tests/tests/tmpfs/Makefile @@ -0,0 +1,52 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Joyent, Inc. +# + +include $(SRC)/Makefile.master + +ROOTOPTPKG = $(ROOT)/opt/os-tests +TESTDIR = $(ROOTOPTPKG)/tests/tmpfs + +PROGS = tmpfs_full +SCRIPTS = tmpfs_badmount \ + tmpfs_enospc + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/test/Makefile.com + +CMDS = $(PROGS:%=$(TESTDIR)/%) $(SCRIPTS:%=$(TESTDIR)/%) +$(CMDS) := FILEMODE = 0555 + +all: $(PROGS) + +install: all $(CMDS) + +lint: + +clobber: clean + -$(RM) $(PROGS) + +clean: + -$(RM) *.o + +$(CMDS): $(TESTDIR) $(PROGS) + +$(TESTDIR): + $(INS.dir) + +$(TESTDIR)/%: %.ksh + $(INS.rename) + +$(TESTDIR)/%: % + $(INS.file) diff --git a/usr/src/test/os-tests/tests/tmpfs/tmpfs_badmount.ksh b/usr/src/test/os-tests/tests/tmpfs/tmpfs_badmount.ksh new file mode 100644 index 0000000000..7e2c4a6095 --- /dev/null +++ b/usr/src/test/os-tests/tests/tmpfs/tmpfs_badmount.ksh @@ -0,0 +1,114 @@ +#!/usr/bin/ksh +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Joyent, Inc. +# + +# +# Test various options to try and mount a tmpfs. Aside from the first to +# verify that we can mount tmpfs at all, these should all fail. +# + +tb_arg0=$(basename $0) +tb_mountpoint="/var/tmp/$0.$$" +tb_mount=/usr/sbin/mount +tb_umount=/usr/sbin/umount + +function fatal +{ + rmdir $tb_mountpoint + typeset msg="$*" + [[ -z "$msg" ]] && msg="test failed" + echo "$tb_arg0: test failed $msg" >&2 + exit 1 +} + +function check_mount +{ + mkdir -p $tb_mountpoint || fatal \ + "failed to make mountpoint $tb_mountpoint" + $tb_mount -F tmpfs swap $tb_mountpoint || fatal \ + "failed to mount tmpfs, check user perms" + $tb_umount $tb_mountpoint || fatal \ + "failed to unmount test point" +} + +function test_one +{ + typeset opts=$1 + + [[ -z "$opts" ]] && fatal "missing required opts" + $tb_mount -F tmpfs -o $opts swap $tb_mountpoint 2>/dev/null + if [[ $? -eq 0 ]]; then + $tb_umount $tb_mountpoint + fatal "successfully mounted with opts $opts, expected failure" + fi +} + +check_mount + +# +# Test invalid percentages. +# +test_one "size=-5%" +test_one "size=200%" +test_one "size=55.55555%" +test_one "size=100.0%" +test_one "size=bad%" +test_one "size=30g%" +test_one "size=%" +test_one "size=%wat" + +# +# Test invalid sizes. Only kmg are valid prefixes. +# +test_one "size=hello;world" +test_one "size=0xnope" +test_one "size=3.14g" +test_one "size=3;14" +test_one "size=thisisanormalsize" +test_one "size=" +test_one "size=100mtry" + +# +# Now, we need to try and trigger a bunch of overflow. We're going to do +# this assuming we're on a 64-bit kernel (which will always overflow a +# 32-bit kernel). +# +test_one "size=20000000000000000000" +test_one "size=1ggggggggggggggggggg" +test_one "size=1mmmmmmmmmmmmmmmmmmm" +test_one "size=1kkkkkkkkkkkkkkkkkkk" +test_one "size=1kkkkkkkkkkkkkkkkkkk" +test_one "size=18014398509481983k" +test_one "size=17592186044416m" +test_one "size=17179869185g" +test_one "size=17179869184g" + +# +# Let's throw a couple bad modes around while we're here. +# +test_one "mode=17777" +test_one "mode=27777" +test_one "mode=37777" +test_one "mode=47777" +test_one "mode=57777" +test_one "mode=67777" +test_one "mode=77777" +test_one "mode=87777" +test_one "mode=97777" +test_one "mode=asdf" +test_one "mode=deadbeef" +test_one "mode=kefka" + +rmdir $tb_mountpoint diff --git a/usr/src/test/os-tests/tests/tmpfs/tmpfs_enospc.ksh b/usr/src/test/os-tests/tests/tmpfs/tmpfs_enospc.ksh new file mode 100644 index 0000000000..a285f306e2 --- /dev/null +++ b/usr/src/test/os-tests/tests/tmpfs/tmpfs_enospc.ksh @@ -0,0 +1,74 @@ +#!/usr/bin/ksh +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Joyent, Inc. +# + +# +# Verify that if we fill up a tmpfs that we can't then perform +# additional things to it that would result in the creation or use of +# kernel memory. +# + +te_arg0=$(basename $0) +te_root=$(dirname $0) +te_bin=$te_root/tmpfs_full +te_mountpoint="/var/tmp/$0.$$" +te_mount=/usr/sbin/mount +te_umount=/usr/sbin/umount +te_testfile=1m +te_mounted= +te_exit=1 + +function fatal +{ + [[ -n "$te_mounted" ]] && $te_umount $te_mountpoint + rmdir $te_mountpoint + typeset msg="$*" + [[ -z "$msg" ]] && msg="test failed" + echo "$te_arg0: test failed $msg" >&2 + exit 1 +} + +function setup +{ + typeset ofile=$te_mountpoint/$te_testfile + + mkdir -p $te_mountpoint || fatal \ + "failed to make mountpoint $te_mountpoint" + $te_mount -F tmpfs swap $te_mountpoint || fatal \ + "failed to mount tmpfs, check user perms" + te_mounted=1 + dd if=/dev/zero of=$ofile bs=1M count=1 2>/dev/null || fatal \ + "failed to create a 1 MB file" + $te_mount -F tmpfs -o remount,size=512k swap $te_mountpoint || + fatal "failed to remount tmpfs" +} + +function run_test +{ + $te_bin $te_mountpoint $te_testfile || fatal "$te_bin failed" +} + +function cleanup +{ + te_mounted= + $te_umount $te_mountpoint || fatal "failed to unmount $te_mountpoint" + rmdir $te_mountpoint || fatal "failed to remove $te_mountpoint" +} + +setup +run_test +cleanup + +exit 0 diff --git a/usr/src/test/os-tests/tests/tmpfs/tmpfs_full.c b/usr/src/test/os-tests/tests/tmpfs/tmpfs_full.c new file mode 100644 index 0000000000..6c6037710b --- /dev/null +++ b/usr/src/test/os-tests/tests/tmpfs/tmpfs_full.c @@ -0,0 +1,94 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +/* + * Given a path to a tmpfs that has already been marked as full, attempt to + * perform certain activities on it, all of which should fail with ENOSPC. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <fcntl.h> +#include <errno.h> +#include <strings.h> +#include <sys/debug.h> +#include <unistd.h> + +int +main(int argc, const char *argv[]) +{ + int fd, ret; + struct statvfs vfs; + + if (argc != 3) { + fprintf(stderr, "test failed: missing path or file\n"); + return (1); + } + + if ((fd = open(argv[1], O_RDONLY)) < 0) { + fprintf(stderr, "test failed: failed to open root %s: %s\n", + argv[1], strerror(errno)); + return (1); + } + + if (fstatvfs(fd, &vfs) != 0) { + fprintf(stderr, "test failed: failed to stat vfs for %s: %s\n", + argv[1], strerror(errno)); + return (1); + } + + if (strncmp("tmpfs", vfs.f_basetype, FSTYPSZ) != 0) { + fprintf(stderr, "test failed: asked to run on non-tmpfs\n"); + return (1); + } + + /* + * Once a few additional bugs in tmpfs are fixed, we should double check + * and make sure that the free space here is actually zero before + * continuing. + */ + + /* + * Go through operations that would create nodes and make sure that they + * all fail. + */ + + ret = openat(fd, "Mnemosyne", O_RDWR | O_CREAT, 0755); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, ENOSPC); + + ret = mkdirat(fd, "Euterpe", 0775); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, ENOSPC); + + ret = symlinkat("/dev/null", fd, "Melpomene"); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, ENOSPC); + + ret = linkat(fd, argv[2], fd, "Urania", 0); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, ENOSPC); + + /* + * Make sure we can't create open extended attributes. + */ + ret = openat(fd, "Lethe", O_RDWR | O_CREAT | O_XATTR); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, ENOSPC); + + return (0); +} diff --git a/usr/src/test/test-runner/cmd/Makefile b/usr/src/test/test-runner/cmd/Makefile index 33e7a61275..948aea9ed8 100644 --- a/usr/src/test/test-runner/cmd/Makefile +++ b/usr/src/test/test-runner/cmd/Makefile @@ -34,4 +34,6 @@ $(ROOTBIN): $(INS.dir) $(ROOTBIN)/%: %.py - $(INS.rename) + $(RM) $@ + $(SED.py) $< > $@ + $(CHMOD) 0555 $@ diff --git a/usr/src/test/test-runner/cmd/run.py b/usr/src/test/test-runner/cmd/run.py index 81e53b210f..4054b12087 100644 --- a/usr/src/test/test-runner/cmd/run.py +++ b/usr/src/test/test-runner/cmd/run.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.6 +#!ON_PYTHON_26 # # This file and its contents are supplied under the terms of the diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run index 3f7498e23b..dcdbf43f95 100644 --- a/usr/src/test/util-tests/runfiles/default.run +++ b/usr/src/test/util-tests/runfiles/default.run @@ -24,9 +24,14 @@ outputdir = /var/tmp/test_results [/opt/util-tests/tests/printf_test] [/opt/util-tests/tests/allowed-ips] +[/opt/util-tests/tests/vnic-mtu] +[/opt/util-tests/tests/bunyan] [/opt/util-tests/tests/xargs_test] +[/opt/util-tests/tests/mqt] +[/opt/util-tests/tests/wqt] + [/opt/util-tests/tests/libnvpair_json] tests = ['json_00_blank', 'json_01_boolean', 'json_02_numbers', 'json_03_empty_arrays', 'json_04_number_arrays', 'json_05_strings', diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile index 4709c7adcd..739b79893f 100644 --- a/usr/src/test/util-tests/tests/Makefile +++ b/usr/src/test/util-tests/tests/Makefile @@ -14,7 +14,6 @@ # Copyright 2014 Garrett D'Amore <garrett@damore.org> # -SUBDIRS = dladm printf xargs -SUBDIRS = dladm libnvpair_json printf xargs +SUBDIRS = dladm libnvpair_json printf xargs mergeq workq include $(SRC)/test/Makefile.com diff --git a/usr/src/test/util-tests/tests/bunyan/Makefile b/usr/src/test/util-tests/tests/bunyan/Makefile new file mode 100644 index 0000000000..5f58bf1614 --- /dev/null +++ b/usr/src/test/util-tests/tests/bunyan/Makefile @@ -0,0 +1,68 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Joyent, Inc. +# + +include $(SRC)/Makefile.master + +ROOTOPTPKG = $(ROOT)/opt/util-tests +TESTDIR = $(ROOTOPTPKG)/tests/bunyan +TESTBIN = $(ROOTOPTPKG)/bin + +PROG = btest + +SCRIPTS = \ + bunyan + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/test/Makefile.com + +OBJS = $(PROG:%=%.o) +SRCS = $(OBJS:%.o=%.c) + +CMDS = $(PROG:%=$(TESTBIN)/%) $(SCRIPTS:%=$(TESTDIR)/%) +$(CMDS) := FILEMODE = 0555 + +DIRS = $(TESTDIR) $(TESTBIN) + +LDLIBS += -lbunyan + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +install: all $(CMDS) + +lint: + +clobber: clean + -$(RM) $(PROG) + +clean: + -$(RM) $(OBJS) + +$(CMDS): $(DIRS) + +$(DIRS): + $(INS.dir) + +$(TESTDIR)/%: %.ksh + $(INS.rename) + +$(TESTDIR)/%: % + $(INS.file) + +$(TESTBIN)/%: % + $(INS.file) diff --git a/usr/src/test/util-tests/tests/bunyan/btest.c b/usr/src/test/util-tests/tests/bunyan/btest.c new file mode 100644 index 0000000000..5239e91f1e --- /dev/null +++ b/usr/src/test/util-tests/tests/bunyan/btest.c @@ -0,0 +1,312 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2014, Joyent, Inc. + */ + +#include <stdio.h> +#include <assert.h> +#include <bunyan.h> +#include <netinet/in.h> +#include <strings.h> + +static void +create_handles(void) +{ + bunyan_logger_t *a, *b, *c; + + assert(bunyan_init("foo", &a) == 0); + assert(bunyan_init("foo", &b) == 0); + assert(bunyan_init("foo", &c) == 0); + bunyan_fini(a); + bunyan_fini(b); + bunyan_fini(c); +} + +static void +create_stream(void) +{ + bunyan_logger_t *a; + + assert(bunyan_init("foo", &a) == 0); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_stream_add(a, "baz", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == EEXIST); + assert(bunyan_stream_add(a, "baz", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == EEXIST); + assert(bunyan_stream_remove(a, "baz") == 0); + assert(bunyan_stream_remove(a, "baz") == ENOENT); + assert(bunyan_stream_remove(a, "foobaz") == ENOENT); + assert(bunyan_stream_remove(a, "blah") == ENOENT); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == EEXIST); + assert(bunyan_stream_add(a, "baz", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_stream_add(a, "debug", BUNYAN_L_DEBUG, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_stream_add(a, "info", BUNYAN_L_INFO, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_stream_add(a, "warn", BUNYAN_L_WARN, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_stream_add(a, "error", BUNYAN_L_ERROR, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_stream_add(a, "fatal", BUNYAN_L_FATAL, + bunyan_stream_fd, (void *)1) == 0); + + bunyan_fini(a); +} + +static void +create_key(void) +{ + bunyan_logger_t *a; + struct in_addr v4; + struct in6_addr v6; + + assert(bunyan_init("foo", &a) == 0); + assert(bunyan_key_remove(a, "blah") == ENOENT); + assert(bunyan_key_add(a, BUNYAN_T_END) == 0); + + assert(bunyan_key_add(a, BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + + assert(bunyan_key_remove(a, "s") == 0); + assert(bunyan_key_remove(a, "s") == ENOENT); + assert(bunyan_key_remove(a, "p") == 0); + assert(bunyan_key_remove(a, "p") == ENOENT); + assert(bunyan_key_remove(a, "v4") == 0); + assert(bunyan_key_remove(a, "v4") == ENOENT); + assert(bunyan_key_remove(a, "v6") == 0); + assert(bunyan_key_remove(a, "v6") == ENOENT); + assert(bunyan_key_remove(a, "b") == 0); + assert(bunyan_key_remove(a, "b") == ENOENT); + assert(bunyan_key_remove(a, "i32") == 0); + assert(bunyan_key_remove(a, "i32") == ENOENT); + assert(bunyan_key_remove(a, "i64") == 0); + assert(bunyan_key_remove(a, "i64") == ENOENT); + assert(bunyan_key_remove(a, "u32") == 0); + assert(bunyan_key_remove(a, "u32") == ENOENT); + assert(bunyan_key_remove(a, "u64") == 0); + assert(bunyan_key_remove(a, "u64") == ENOENT); + assert(bunyan_key_remove(a, "d") == 0); + assert(bunyan_key_remove(a, "d") == ENOENT); + assert(bunyan_key_remove(a, "i64s") == 0); + assert(bunyan_key_remove(a, "i64s") == ENOENT); + assert(bunyan_key_remove(a, "u64s") == 0); + assert(bunyan_key_remove(a, "u64s") == ENOENT); + + bunyan_fini(a); +} + +static void +bad_level(void) +{ + bunyan_logger_t *a; + + assert(bunyan_init("bad level", &a) == 0); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE - 1, + bunyan_stream_fd, (void *)1) == EINVAL); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE + 1, + bunyan_stream_fd, (void *)1) == EINVAL); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_DEBUG - 1, + bunyan_stream_fd, (void *)1) == EINVAL); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_INFO + 1, + bunyan_stream_fd, (void *)1) == EINVAL); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_WARN - 1, + bunyan_stream_fd, (void *)1) == EINVAL); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_ERROR + 1, + bunyan_stream_fd, (void *)1) == EINVAL); + assert(bunyan_stream_add(a, "bar", BUNYAN_L_FATAL - 1, + bunyan_stream_fd, (void *)1) == EINVAL); + assert(bunyan_stream_add(a, "bar", -5, + bunyan_stream_fd, (void *)1) == EINVAL); + + bunyan_fini(a); +} + +static void +basic_log(void) +{ + bunyan_logger_t *a; + + assert(bunyan_init("basic", &a) == 0); + assert(bunyan_stream_add(a, "foo", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_trace(a, "trace", BUNYAN_T_END) == 0); + assert(bunyan_debug(a, "debug", BUNYAN_T_END) == 0); + assert(bunyan_info(a, "info", BUNYAN_T_END) == 0); + assert(bunyan_warn(a, "warn", BUNYAN_T_END) == 0); + assert(bunyan_error(a, "error", BUNYAN_T_END) == 0); + assert(bunyan_fatal(a, "fatal", BUNYAN_T_END) == 0); + + bunyan_fini(a); +} + +static void +crazy_log(void) +{ + bunyan_logger_t *a; + struct in_addr v4; + struct in6_addr v6; + + bzero(&v4, sizeof (struct in_addr)); + bzero(&v6, sizeof (struct in6_addr)); + + assert(bunyan_init("basic", &a) == 0); + assert(bunyan_stream_add(a, "foo", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_trace(a, "trace", BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + assert(bunyan_debug(a, "debug", BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + assert(bunyan_info(a, "info", BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + assert(bunyan_warn(a, "warn", BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + assert(bunyan_error(a, "error", BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + assert(bunyan_fatal(a, "fatal", BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + + bunyan_fini(a); +} + +static void +child_log(void) +{ + bunyan_logger_t *a, *child; + struct in_addr v4; + struct in6_addr v6; + + bzero(&v4, sizeof (struct in_addr)); + bzero(&v6, sizeof (struct in6_addr)); + + assert(bunyan_init("child", &a) == 0); + assert(bunyan_stream_add(a, "foo", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_child(a, &child, BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + + bunyan_fini(a); + assert(bunyan_trace(child, "trace", BUNYAN_T_END) == 0); + assert(bunyan_debug(child, "debug", BUNYAN_T_END) == 0); + assert(bunyan_info(child, "info", BUNYAN_T_END) == 0); + assert(bunyan_warn(child, "warn", BUNYAN_T_END) == 0); + assert(bunyan_error(child, "error", BUNYAN_T_END) == 0); + assert(bunyan_fatal(child, "fatal", BUNYAN_T_END) == 0); + + bunyan_fini(child); +} + +static void +crazy_child(void) +{ + bunyan_logger_t *a, *child; + struct in_addr v4; + struct in6_addr v6; + + bzero(&v4, sizeof (struct in_addr)); + bzero(&v6, sizeof (struct in6_addr)); + + assert(bunyan_init("crazy child", &a) == 0); + assert(bunyan_stream_add(a, "foo", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_key_add(a, BUNYAN_T_STRING, "s", "foo", + BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4, + BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE, + BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969, + BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323, + BUNYAN_T_DOUBLE, "d", 3.14, + BUNYAN_T_INT64STR, "i64s", (uint64_t)12345, + BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0); + assert(bunyan_child(a, &child, BUNYAN_T_END) == 0); + bunyan_fini(a); + + assert(bunyan_stream_remove(child, "foo") == 0); + assert(bunyan_stream_add(child, "bar", BUNYAN_L_TRACE, + bunyan_stream_fd, (void *)1) == 0); + assert(bunyan_key_remove(child, "u64s") == 0); + assert(bunyan_trace(child, "trace", BUNYAN_T_END) == 0); + assert(bunyan_debug(child, "debug", BUNYAN_T_END) == 0); + assert(bunyan_info(child, "info", BUNYAN_T_END) == 0); + assert(bunyan_warn(child, "warn", BUNYAN_T_END) == 0); + assert(bunyan_error(child, "error", BUNYAN_T_END) == 0); + assert(bunyan_fatal(child, "fatal", BUNYAN_T_END) == 0); + + bunyan_fini(child); +} + +int +main(void) +{ + create_handles(); + create_stream(); + create_key(); + bad_level(); + basic_log(); + crazy_log(); + child_log(); + crazy_child(); + + return (0); +} diff --git a/usr/src/test/os-tests/runfiles/omnios.run b/usr/src/test/util-tests/tests/bunyan/bunyan.ksh index 4e73ebc8b3..4ec0f4bd62 100644 --- a/usr/src/test/os-tests/runfiles/omnios.run +++ b/usr/src/test/util-tests/tests/bunyan/bunyan.ksh @@ -1,3 +1,4 @@ +#! /usr/bin/ksh # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. @@ -10,19 +11,16 @@ # # -# Copyright (c) 2012 by Delphix. All rights reserved. +# Copyright (c) 2014, Joyent, Inc. # -[DEFAULT] -pre = -verbose = False -quiet = False -timeout = 60 -post = -outputdir = /var/tmp/test_results +# +# Simple wrapper for the classic test.out +# + +set -o errexit -[/opt/os-tests/tests/poll_test] -user = root +btest_root=$(dirname $0)/../.. +btest_bin=$btest_root/bin/btest -[/opt/os-tests/tests/sigqueue] -tests = ['sigqueue_queue_size'] +LD_PRELOAD=libumem.so UMEM_DEBUG=default $btest_bin >/dev/null diff --git a/usr/src/test/util-tests/tests/dladm/Makefile b/usr/src/test/util-tests/tests/dladm/Makefile index df3997656c..a71332b016 100644 --- a/usr/src/test/util-tests/tests/dladm/Makefile +++ b/usr/src/test/util-tests/tests/dladm/Makefile @@ -17,7 +17,7 @@ include $(SRC)/cmd/Makefile.cmd include $(SRC)/test/Makefile.com ROOTOPTPKG = $(ROOT)/opt/util-tests/tests -PROG = allowed-ips +PROG = allowed-ips vnic-mtu ROOTPROG = $(PROG:%=$(ROOTOPTPKG)/%) diff --git a/usr/src/test/util-tests/tests/dladm/vnic-mtu.ksh b/usr/src/test/util-tests/tests/dladm/vnic-mtu.ksh new file mode 100644 index 0000000000..49daa74f3b --- /dev/null +++ b/usr/src/test/util-tests/tests/dladm/vnic-mtu.ksh @@ -0,0 +1,116 @@ +#!/bin/ksh +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Joyent, Inc. +# + +# +# The purpose of this is to test the MTU property on VNICs, using both +# temporary and persistent properties. To do this, we create an +# Etherstub and then create various VNICs on top of it. +# + +vm_arg0="$(basename $0)" +vm_stub="teststub$$" +vm_vnic="testvnic$$" + +VM_MTU_MIN=576 +VM_MTU_MAX=9000 + +fatal() +{ + typeset msg="$*" + [[ -z "$msg" ]] && msg="failed" + echo "TEST_FAIL: $vm_arg0: $msg" >&2 + + # Try to clean up just in case + dladm delete-vnic $vm_vnic 2>/dev/null + dladm delete-etherstub $vm_stub 2>/dev/null + exit 1 +} + +# +# Validate that the MTU of the datalink dev has the MTU that we expect +# +validate_mtu() +{ + typeset dev=$1 + typeset mtu=$2 + typeset val + + [[ -z "$dev" ]] && fatal "missing required device" + [[ -z "$mtu" ]] && fatal "missing required mtu" + val=$(dladm show-linkprop -c -p mtu -o value $dev) + [[ $? -eq 0 ]] || fatal "failed to get MTU for $dev" + (( $val == $mtu )) || fatal \ + "mtu mismatch on $dev: expected $mtu, got $val" +} + +delete_stub() +{ + dladm delete-etherstub $vm_stub || fatal \ + "failed to delete stub $vm_stub" +} + +create_stub() +{ + dladm create-etherstub $vm_stub || fatal \ + "failed to create stub" + validate_mtu $vm_stub $VM_MTU_MAX +} + +delete_vnic() +{ + dladm delete-vnic $vm_vnic || fatal "failed to delete vnic $vm_vnic" +} + +test_vnic_pass() +{ + typeset mtu=$1 + typeset flags=$2 + + [[ -z "$mtu" ]] && fatal "missing required mtu" + dladm create-vnic $flags -l $vm_stub -p mtu=$mtu $vm_vnic || fatal \ + "failed tocreate vnic: $vm_vnic" + validate_mtu "$vm_vnic" "$mtu" + delete_vnic +} + +test_vnic_fail() +{ + typeset mtu=$1 + typeset flags=$2 + + [[ -z "$mtu" ]] && fatal "missing required mtu" + dladm create-vnic $flags -l $vm_stub -p mtu=$mtu \ + $vm_vnic 2>/dev/null && fatal \ + "created vnic with mtu $mtu, but failure expected" +} + +test_pass() +{ + typeset flags=$1 + + create_stub + test_vnic_pass 1500 $flags + test_vnic_pass 1400 $flags + test_vnic_pass $VM_MTU_MIN $flags + test_vnic_pass $VM_MTU_MAX $flags + test_vnic_fail $((($VM_MTU_MIN - 1))) $flags + test_vnic_fail $((($VM_MTU_MAX + 1))) $flags + delete_stub +} + +test_pass "-t" +test_pass +echo "TEST PASS: $vm_arg0" diff --git a/usr/src/test/util-tests/tests/libnvpair_json/Makefile b/usr/src/test/util-tests/tests/libnvpair_json/Makefile index d1d3585b02..3b48e0b630 100644 --- a/usr/src/test/util-tests/tests/libnvpair_json/Makefile +++ b/usr/src/test/util-tests/tests/libnvpair_json/Makefile @@ -10,14 +10,14 @@ # # -# Copyright (c) 2014 Joyent, Inc. +# Copyright 2015 Joyent, Inc. # include $(SRC)/Makefile.master ROOTOPTPKG = $(ROOT)/opt/util-tests TESTDIR = $(ROOTOPTPKG)/tests/libnvpair_json -ROOTBINDIR = $(ROOTOPTPKG)/bin +TESTBIN = $(ROOTOPTPKG)/bin PROG = print_json @@ -38,9 +38,11 @@ include $(SRC)/test/Makefile.com OBJS = $(PROG:%=%.o) SRCS = $(OBJS:%.o=%.c) -CMDS = $(PROG:%=$(ROOTBINDIR)/%) $(SCRIPTS:%=$(TESTDIR)/%) +CMDS = $(PROG:%=$(TESTBIN)/%) $(SCRIPTS:%=$(TESTDIR)/%) $(CMDS) := FILEMODE = 0555 +DIRS = $(TESTDIR) $(TESTBIN) + LDLIBS += -lnvpair LINTFLAGS += -erroff=E_FUNC_ARG_UNUSED @@ -61,16 +63,13 @@ clobber: clean clean: -$(RM) $(OBJS) -$(CMDS): $(TESTDIR) $(PROG) +$(CMDS): $(DIRS) -$(ROOTBINDIR): - $(INS.dir) - -$(ROOTBINDIR)/%: % - $(INS.file) - -$(TESTDIR): +$(DIRS): $(INS.dir) $(TESTDIR)/%: %.ksh $(INS.rename) + +$(TESTBIN)/%: % + $(INS.file) diff --git a/usr/src/test/util-tests/tests/libnvpair_json/json_08_large_data.ksh b/usr/src/test/util-tests/tests/libnvpair_json/json_08_large_data.ksh new file mode 100644 index 0000000000..ca19e10d06 --- /dev/null +++ b/usr/src/test/util-tests/tests/libnvpair_json/json_08_large_data.ksh @@ -0,0 +1,37 @@ +#!/bin/ksh +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015, Joyent, Inc. +# + +DIR=$(dirname $(whence $0)) +. ${DIR}/json_common + +BASELINE="$(cat <<EOF +{\ +"o":[\ +$(for i in {1..50}; do + printf '"%s",' 'some_very_big_string_that_takes_up_space' +done)\ +"end"\ +]\ +} +EOF)" + +OUTPUT="$(${DIR}/../../bin/print_json <<-EOF +add_string_array "o" $(for i in {1..50}; do + printf '"%s" ' 'some_very_big_string_that_takes_up_space' +done)"end"; +EOF)" + +complete diff --git a/usr/src/test/util-tests/tests/mergeq/Makefile b/usr/src/test/util-tests/tests/mergeq/Makefile new file mode 100644 index 0000000000..ef6c6abb99 --- /dev/null +++ b/usr/src/test/util-tests/tests/mergeq/Makefile @@ -0,0 +1,64 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Joyent, Inc. +# + +include $(SRC)/Makefile.master + +ROOTOPTPKG = $(ROOT)/opt/util-tests +TESTDIR = $(ROOTOPTPKG)/tests/mergeq + +PROG = mqt +OBJS = mqt.o mergeq.o + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/Makefile.ctf +include $(SRC)/test/Makefile.com + +CMDS = $(PROG:%=$(TESTDIR)/%) +$(CMDS) := FILEMODE = 0555 + +CPPFLAGS += -I$(SRC)/lib/mergeq -D_REENTRANT +LDLIBS += -lumem + +all: $(PROG) + +install: all $(CMDS) + +lint: lint_SRCS + +clobber: clean + -$(RM) $(PROG) + +clean: + -$(RM) $(OBJS) + +%.o: %.c + $(COMPILE.c) -o $@ -c $< + $(POST_PROCESS_O) + +%.o: $(SRC)/lib/mergeq/%.c + $(COMPILE.c) -o $@ -c $< + $(POST_PROCESS_O) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +$(CMDS): $(TESTDIR) $(PROG) + +$(TESTDIR): + $(INS.dir) + +$(TESTDIR)/%: % + $(INS.file) diff --git a/usr/src/test/util-tests/tests/mergeq/mqt.c b/usr/src/test/util-tests/tests/mergeq/mqt.c new file mode 100644 index 0000000000..e61e9173d2 --- /dev/null +++ b/usr/src/test/util-tests/tests/mergeq/mqt.c @@ -0,0 +1,217 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +/* + * mergeq testing routines + */ + +#include <mergeq.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +const char * +_umem_debug_init() +{ + return ("default,verbose"); +} + +const char * +_umem_logging_init(void) +{ + return ("fail,contents"); +} + +void * +mergeq_alloc(size_t size) +{ + return (malloc(size)); +} + +/*ARGSUSED*/ +void +mergeq_free(void *buf, size_t size) +{ + free(buf); +} + +static int +mqt_int(void *first, void *second, void **outp, void *arg) +{ + uintptr_t a, b, c; + a = (uintptr_t)first; + b = (uintptr_t)second; + c = a + b; + *outp = (void *)c; + + return (0); +} + +static int +mqt_append(void *first, void *second, void **outp, void *arg) +{ + char *out; + + /* Yes, this leaks, don't worry about it for the test */ + if (asprintf(&out, "%s%s", first, second) != -1) { + *outp = out; + return (0); + } + return (-1); +} + +static int +mqt_fatal(void *first, void *second, void **outp, void *arg) +{ + return (-1); +} + +/* + * Test structures and cases. We really want mq_args to be a flexible array + * member, but then we cant initialize it. Thus we set a fixed size number of + * entries. + */ +typedef struct mq_test { + const char *mq_desc; /* test description/name */ + mergeq_proc_f *mq_proc; /* processing function */ + int mq_rval; /* mergeq_merge return value */ + int mq_uerr; /* user error, if any */ + boolean_t mq_strcmp; /* use strcmp rather than == */ + void *mq_result; /* expected result */ + void **mq_args; /* argument array */ +} mq_test_t; + +static void *mqt_empty_args[] = { NULL }; +static void *mqt_single_args[] = { (void *)42, NULL }; +static void *mqt_double_args[] = { (void *)42, (void *)27, NULL }; +static void *mqt_wrap_args[] = { + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, NULL +}; +static void *mqt_grow_args[] = { + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, NULL +}; +static void *mqt_order_args[] = { "l", "e", "g", "e", "n", "d", " ", "o", "f", + " ", "z", "e", "l", "d", "a", NULL }; + + +static mq_test_t mq_tests[] = { + { "empty", mqt_int, 0, 0, B_FALSE, NULL, mqt_empty_args }, + { "single", mqt_int, 0, 0, B_FALSE, (void *)42, mqt_single_args }, + { "double", mqt_int, 0, 0, B_FALSE, (void *)69, mqt_double_args }, + { "wrap", mqt_int, 0, 0, B_FALSE, (void *)64, mqt_wrap_args }, + { "grow", mqt_int, 0, 0, B_FALSE, (void *)92, mqt_grow_args }, + { "fatal", mqt_fatal, MERGEQ_UERROR, -1, B_FALSE, NULL, + mqt_double_args }, + { "order", mqt_append, 0, 0, B_TRUE, "alegend of zeld", mqt_order_args } +}; + +#define NMQ_TESTS (sizeof (mq_tests) / sizeof (mq_test_t)) + +static void +mq_test_run(mergeq_t *mqp, mq_test_t *mqt) +{ + int ret, err; + void **itemp = mqt->mq_args; + void *out; + + while (*itemp != NULL) { + if ((ret = mergeq_add(mqp, *itemp)) != 0) { + (void) fprintf(stderr, + "test %s: failed to add item: %s\n", + mqt->mq_desc, strerror(errno)); + exit(1); + } + itemp++; + } + + ret = mergeq_merge(mqp, mqt->mq_proc, NULL, &out, &err); + if (ret != mqt->mq_rval) { + (void) fprintf(stderr, "test %s: got incorrect rval. " + "Expected %d, got %d\n", mqt->mq_desc, mqt->mq_rval, ret); + exit(1); + } + + if (ret == MERGEQ_UERROR && err != mqt->mq_uerr) { + (void) fprintf(stderr, "test %s: got incorrect user error. " + "Expected %d, got %d\n", mqt->mq_desc, mqt->mq_uerr, err); + exit(1); + } + + if (ret == 0) { + if (mqt->mq_strcmp == B_TRUE && + strcmp(out, mqt->mq_result) != 0) { + (void) fprintf(stderr, "test %s: got unexpected " + "result: %s, expected %s\n", mqt->mq_desc, out, + mqt->mq_result); + exit(1); + } else if (mqt->mq_strcmp == B_FALSE && out != mqt->mq_result) { + (void) fprintf(stderr, "test %s: got unexpected " + "result: %p, expected %p\n", mqt->mq_desc, out, + mqt->mq_result); + exit(1); + } + } +} + +int +main(void) +{ + int ret, i, t; + mergeq_t *mqp; + int nthreads[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, -1 }; + + for (t = 0; nthreads[t] != -1; t++) { + printf("Beginning tests with %d threads\n", nthreads[t]); + if ((ret = mergeq_init(&mqp, nthreads[t])) != 0) { + fprintf(stderr, "failed to init mergeq: %s\n", + strerror(errno)); + return (1); + } + + for (i = 0; i < NMQ_TESTS; i++) { + mq_test_run(mqp, &mq_tests[i]); + } + + mergeq_fini(mqp); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/workq/Makefile b/usr/src/test/util-tests/tests/workq/Makefile new file mode 100644 index 0000000000..ab5455fd86 --- /dev/null +++ b/usr/src/test/util-tests/tests/workq/Makefile @@ -0,0 +1,64 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Joyent, Inc. +# + +include $(SRC)/Makefile.master + +ROOTOPTPKG = $(ROOT)/opt/util-tests +TESTDIR = $(ROOTOPTPKG)/tests/mergeq + +PROG = wqt +OBJS = wqt.o workq.o + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/Makefile.ctf +include $(SRC)/test/Makefile.com + +CMDS = $(PROG:%=$(TESTDIR)/%) +$(CMDS) := FILEMODE = 0555 + +CPPFLAGS += -I$(SRC)/lib/mergeq -D_REENTRANT +LDLIBS += -lumem + +all: $(PROG) + +install: all $(CMDS) + +lint: lint_SRCS + +clobber: clean + -$(RM) $(PROG) + +clean: + -$(RM) $(OBJS) + +%.o: %.c + $(COMPILE.c) -o $@ -c $< + $(POST_PROCESS_O) + +%.o: $(SRC)/lib/mergeq/%.c + $(COMPILE.c) -o $@ -c $< + $(POST_PROCESS_O) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +$(CMDS): $(TESTDIR) $(PROG) + +$(TESTDIR): + $(INS.dir) + +$(TESTDIR)/%: % + $(INS.file) diff --git a/usr/src/test/util-tests/tests/workq/wqt.c b/usr/src/test/util-tests/tests/workq/wqt.c new file mode 100644 index 0000000000..bda0b4a9e5 --- /dev/null +++ b/usr/src/test/util-tests/tests/workq/wqt.c @@ -0,0 +1,196 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +/* + * workq testing routines + * + * What we want to guarantee is that every function is executed exactly once. To + * that end we have the callback function basically increment a global in the + * test around a mutex. + */ + +#include <workq.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <thread.h> +#include <synch.h> + +mutex_t wqt_lock = ERRORCHECKMUTEX; +uintptr_t wqt_count; + +const char * +_umem_debug_init() +{ + return ("default,verbose"); +} + +const char * +_umem_logging_init(void) +{ + return ("fail,contents"); +} + +void * +workq_alloc(size_t size) +{ + return (malloc(size)); +} + +/*ARGSUSED*/ +void +workq_free(void *buf, size_t size) +{ + free(buf); +} + +/*ARGSUSED*/ +int +wqt_fatal(void *item, void *arg) +{ + return (-1); +} + +int +wqt_add(void *item, void *arg) +{ + uintptr_t a = (uintptr_t)item; + + mutex_enter(&wqt_lock); + wqt_count += a; + mutex_exit(&wqt_lock); + + return (0); +} + +typedef struct wq_test { + const char *wq_desc; /* test description/name */ + workq_proc_f *wq_proc; /* processing function */ + int wq_rval; /* workq_work return value */ + int wq_uerr; /* user error, if any */ + uintptr_t wq_sum; /* expected sum */ + void **wq_args; /* argument array */ +} wq_test_t; + +static void *wqt_empty_args[] = { NULL }; +static void *wqt_single_args[] = { (void *)42, NULL }; +static void *wqt_double_args[] = { (void *)42, (void *)27, NULL }; +static void *wqt_wrap_args[] = { + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, NULL +}; +static void *wqt_grow_args[] = { + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, + (void *)1, (void *)1, NULL +}; + +static wq_test_t wq_tests[] = { + { "empty", wqt_add, 0, 0, NULL, wqt_empty_args }, + { "single", wqt_add, 0, 0, 42, wqt_single_args }, + { "double", wqt_add, 0, 0, 69, wqt_double_args }, + { "wrap", wqt_add, 0, 0, 64, wqt_wrap_args }, + { "grow", wqt_add, 0, 0, 92, wqt_grow_args }, + { "fatal", wqt_fatal, WORKQ_UERROR, -1, -1, wqt_double_args } +}; + +#define NWQ_TESTS (sizeof (wq_tests) / sizeof (wq_test_t)) + +static void +wq_test_run(workq_t *wqp, wq_test_t *wqt) +{ + int ret, err; + void **itemp = wqt->wq_args; + + while (*itemp != NULL) { + if ((ret = workq_add(wqp, *itemp)) != 0) { + (void) fprintf(stderr, "test %s: failed to add item: " + "%s\n", wqt->wq_desc, strerror(errno)); + exit(1); + } + itemp++; + } + + wqt_count = 0; + ret = workq_work(wqp, wqt->wq_proc, NULL, &err); + if (ret != wqt->wq_rval) { + (void) fprintf(stderr, "test %s: got incorrect rval. " + "Expected %d, got %d (%d)\n", wqt->wq_desc, wqt->wq_rval, + ret, errno); + exit(1); + } + + if (ret == WORKQ_UERROR && err != wqt->wq_uerr) { + (void) fprintf(stderr, "test %s: got incorrect user error. " + "Expected %d, got %d\n", wqt->wq_desc, wqt->wq_uerr, err); + exit(1); + } + + if (ret == 0 && wqt_count != wqt->wq_sum) { + (void) fprintf(stderr, "test %s: got unexpected " + "result: %d, expected %d\n", wqt->wq_desc, wqt_count, + wqt->wq_sum); + exit(1); + } +} + +int +main(void) +{ + int ret, i, t; + workq_t *wqp; + int nthreads[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, -1 }; + + for (t = 0; nthreads[t] != -1; t++) { + printf("Beginning tests with %d threads\n", nthreads[t]); + if ((ret = workq_init(&wqp, nthreads[t])) != 0) { + fprintf(stderr, "failed to init workq: %s\n", + strerror(errno)); + return (1); + } + + for (i = 0; i < NWQ_TESTS; i++) { + wq_test_run(wqp, &wq_tests[i]); + } + + workq_fini(wqp); + } + + + return (0); +} |
