docs: Move release notes to their own section.
[nbdkit/ericb.git] / tests / test.c
blob7dfe422ebdf01281790b50478e08f28d1caf03f5
1 /* nbdkit
2 * Copyright (C) 2013 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42 #include <signal.h>
43 #include <errno.h>
44 #include <assert.h>
46 #include "test.h"
48 /* 'test_start_nbdkit' below makes assumptions about the format of
49 * these strings.
51 #define TEST_NBDKIT_TEMPLATE "/tmp/nbdkitXXXXXX"
52 struct test_nbdkit {
53 char tmpdir[ 17 + 1]; /* template, NUL */
54 char sockpath[ 17 + 5 + 1]; /* template, "/sock", NUL */
55 char unixsockpath[5 + 17 + 5 + 1]; /* "unix:", template, "/sock", NUL */
56 char pidpath[ 17 + 4 + 1]; /* template, "/pid", NUL */
57 pid_t pid;
58 struct test_nbdkit *next;
60 const struct test_nbdkit template = {
61 .tmpdir = TEST_NBDKIT_TEMPLATE,
62 .sockpath = TEST_NBDKIT_TEMPLATE "/sock",
63 .unixsockpath = "unix:" TEST_NBDKIT_TEMPLATE "/sock",
64 .pidpath = TEST_NBDKIT_TEMPLATE "/pid",
67 static struct test_nbdkit *head;
69 pid_t pid = 0;
70 const char *sock = NULL;
71 const char *server[2] = { NULL, NULL };
73 static void
74 cleanup (void)
76 int status;
77 struct test_nbdkit *next;
79 while (head) {
80 if (head->pid > 0) {
81 assert (!pid || pid == head->pid);
82 pid = 0;
83 kill (head->pid, SIGTERM);
85 /* Check the status of nbdkit is normal on exit. */
86 if (waitpid (head->pid, &status, 0) == -1) {
87 perror ("waitpid");
88 _exit (EXIT_FAILURE);
90 if (WIFEXITED (status) && WEXITSTATUS (status) != 0) {
91 _exit (WEXITSTATUS (status));
93 if (WIFSIGNALED (status)) {
94 /* Note that nbdkit is supposed to catch the signal we send and
95 * exit cleanly, so the following shouldn't happen.
97 fprintf (stderr, "nbdkit terminated by signal %d\n", WTERMSIG (status));
98 _exit (EXIT_FAILURE);
100 if (WIFSTOPPED (status)) {
101 fprintf (stderr, "nbdkit stopped by signal %d\n", WSTOPSIG (status));
102 _exit (EXIT_FAILURE);
106 unlink (head->pidpath);
107 unlink (head->sockpath);
108 rmdir (head->tmpdir);
110 next = head->next;
111 free (head);
112 head = next;
117 test_start_nbdkit (const char *arg, ...)
119 size_t i, len;
120 struct test_nbdkit *kit = malloc (sizeof *kit);
122 if (!kit) {
123 perror ("malloc");
124 return -1;
126 *kit = template;
127 if (mkdtemp (kit->tmpdir) == NULL) {
128 perror ("mkdtemp");
129 free (kit);
130 return -1;
132 len = strlen (kit->tmpdir);
133 memcpy (kit->sockpath, kit->tmpdir, len);
134 memcpy (kit->unixsockpath+5, kit->tmpdir, len);
135 memcpy (kit->pidpath, kit->tmpdir, len);
137 kit->pid = fork ();
138 if (kit->pid == 0) { /* Child (nbdkit). */
139 const char *p;
140 #define MAX_ARGS 64
141 const char *argv[MAX_ARGS+1];
142 va_list args;
144 argv[0] = "nbdkit";
145 argv[1] = "-U";
146 argv[2] = kit->sockpath;
147 argv[3] = "-P";
148 argv[4] = kit->pidpath;
149 argv[5] = "-f";
150 argv[6] = "-v";
151 argv[7] = arg;
152 i = 8;
154 va_start (args, arg);
155 while ((p = va_arg (args, const char *)) != NULL) {
156 if (i >= MAX_ARGS)
157 abort ();
158 argv[i] = p;
159 ++i;
161 va_end (args);
162 argv[i] = NULL;
164 execvp ("nbdkit", (char **) argv);
165 perror ("exec: nbdkit");
166 _exit (EXIT_FAILURE);
169 /* Ensure nbdkit is killed and temporary files are deleted when the
170 * main program exits.
172 if (head)
173 kit->next = head;
174 else
175 atexit (cleanup);
176 head = kit;
177 pid = kit->pid;
178 sock = kit->sockpath;
179 server[0] = kit->unixsockpath;
181 /* Wait for the pidfile to turn up, which indicates that nbdkit has
182 * started up successfully and is ready to serve requests. However
183 * if 'pid' exits in this time it indicates a failure to start up.
184 * Also there is a timeout in case nbdkit hangs.
186 for (i = 0; i < NBDKIT_START_TIMEOUT; ++i) {
187 if (waitpid (pid, NULL, WNOHANG) == pid)
188 goto early_exit;
190 if (kill (pid, 0) == -1) {
191 if (errno == ESRCH) {
192 early_exit:
193 fprintf (stderr,
194 "%s FAILED: nbdkit exited before starting to serve files\n",
195 program_name);
196 pid = 0;
197 return -1;
199 perror ("kill");
202 if (access (kit->pidpath, F_OK) == 0)
203 break;
205 sleep (1);
208 return 0;