r21039: Test some more failure paths (trying to increase the lcov score).
[Samba.git] / source / torture / subunit.c
blobce9bc66b9d641fb0e51fc31a4185ad0c7e3b189b
1 /*
2 Unix SMB/CIFS implementation.
3 Run subunit tests
4 Copyright (C) Jelmer Vernooij 2006
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
22 #include "system/dir.h"
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "torture/ui.h"
26 #include "torture/torture.h"
27 #include "torture/proto.h"
29 struct torture_suite *torture_subunit_suite_create(TALLOC_CTX *mem_ctx,
30 const char *path)
32 struct torture_suite *suite = talloc_zero(mem_ctx, struct torture_suite);
34 suite->path = talloc_strdup(suite, path);
35 suite->name = talloc_strdup(suite, strrchr(path, '/')?strrchr(path, '/')+1:
36 path);
37 suite->description = talloc_asprintf(suite, "Subunit test %s", suite->name);
39 return suite;
42 bool torture_subunit_load_testsuites(const char *directory, bool recursive,
43 struct torture_suite *parent)
45 DIR *dir;
46 struct dirent *entry;
47 char *filename;
48 bool exists;
50 if (parent == NULL)
51 parent = torture_root;
53 dir = opendir(directory);
54 if (dir == NULL)
55 return true;
57 while((entry = readdir(dir))) {
58 struct torture_suite *child;
59 if (entry->d_name[0] == '.')
60 continue;
62 filename = talloc_asprintf(NULL, "%s/%s", directory, entry->d_name);
64 if (!recursive && directory_exist(filename)) {
65 talloc_free(filename);
66 continue;
69 if (directory_exist(filename)) {
70 child = torture_find_suite(parent, entry->d_name);
71 exists = (child != NULL);
72 if (child == NULL)
73 child = torture_suite_create(parent, entry->d_name);
74 torture_subunit_load_testsuites(filename, true, child);
75 } else {
76 child = torture_subunit_suite_create(parent, filename);
77 exists = false;
80 if (!exists) {
81 torture_suite_add_suite(parent, child);
84 talloc_free(filename);
87 closedir(dir);
89 return true;
92 static pid_t piped_child(char* const command[], int *f_stdout, int *f_stderr)
94 pid_t pid;
95 int sock_out[2], sock_err[2];
97 if (pipe(sock_out) == -1) {
98 DEBUG(0, ("socketpair: %s", strerror(errno)));
99 return -1;
102 if (pipe(sock_err) == -1) {
103 DEBUG(0, ("socketpair: %s", strerror(errno)));
104 return -1;
107 *f_stdout = sock_out[0];
108 *f_stderr = sock_err[0];
110 pid = fork();
112 if (pid == -1) {
113 DEBUG(0, ("fork: %s", strerror(errno)));
114 return -1;
117 if (pid == 0) {
118 close(0);
119 close(1);
120 close(2);
121 close(sock_out[0]);
122 close(sock_err[0]);
124 open("/dev/null", O_RDONLY);
125 dup2(sock_out[1], 1);
126 dup2(sock_err[1], 2);
127 execvp(command[0], command);
128 exit(-1);
131 close(sock_out[1]);
132 close(sock_err[1]);
134 return pid;
137 enum subunit_field { SUBUNIT_TEST, SUBUNIT_SUCCESS, SUBUNIT_FAILURE,
138 SUBUNIT_SKIP };
140 static void run_subunit_message(struct torture_context *context,
141 enum subunit_field field,
142 const char *name,
143 const char *comment)
145 struct torture_test test;
147 ZERO_STRUCT(test);
148 test.name = name;
150 switch (field) {
151 case SUBUNIT_TEST:
152 test.description = comment;
153 torture_ui_test_start(context, NULL, &test);
154 break;
155 case SUBUNIT_FAILURE:
156 context->active_test = &test;
157 torture_ui_test_result(context, TORTURE_FAIL, comment);
158 context->active_test = NULL;
159 break;
160 case SUBUNIT_SUCCESS:
161 context->active_test = &test;
162 torture_ui_test_result(context, TORTURE_OK, comment);
163 context->active_test = NULL;
164 break;
165 case SUBUNIT_SKIP:
166 context->active_test = &test;
167 torture_ui_test_result(context, TORTURE_SKIP, comment);
168 context->active_test = NULL;
169 break;
173 bool torture_subunit_run_suite(struct torture_context *context,
174 struct torture_suite *suite)
176 static char *command[2];
177 int fd_out, fd_err;
178 pid_t pid;
179 size_t size;
180 char *p, *q;
181 char *comment = NULL;
182 char *name = NULL;
183 enum subunit_field lastfield;
184 int status;
185 char buffer[4096];
186 size_t offset = 0;
189 command[0] = talloc_strdup(context, suite->path);
190 command[1] = NULL;
192 pid = piped_child(command, &fd_out, &fd_err);
193 if (pid == -1)
194 return false;
196 while (1) {
197 fd_set fds;
198 char *eol;
200 FD_ZERO(&fds);
202 FD_SET(fd_out, &fds);
203 FD_SET(fd_err, &fds);
205 if (select(MAX(fd_out,fd_err)+1, &fds, NULL, NULL, NULL) <= 0) break;
207 if (FD_ISSET(fd_err, &fds)) {
208 size = read(fd_err, buffer+offset, sizeof(buffer) - (offset+1));
209 if (size <= 0) break;
210 write(2, buffer+offset, size);
211 continue;
214 if (!FD_ISSET(fd_out, &fds)) continue;
216 size = read(fd_out, buffer+offset, sizeof(buffer) - (offset+1));
218 if (size <= 0) break;
220 buffer[offset+size] = '\0';
222 write(1, buffer+offset, size);
224 for (p = buffer; p; p = eol+1) {
225 eol = strchr(p, '\n');
226 if (eol == NULL)
227 break;
229 *eol = '\0';
231 if (comment != NULL && strcmp(p, "]") == 0) {
232 run_subunit_message(context, lastfield, name, comment);
233 talloc_free(name); name = NULL;
234 talloc_free(comment); comment = NULL;
235 } else if (comment != NULL) {
236 comment = talloc_append_string(context, comment, p);
237 } else {
238 q = strchr(p, ':');
239 if (q == NULL) {
240 torture_comment(context, "Invalid line `%s'\n", p);
241 continue;
244 *q = '\0';
245 if (!strcmp(p, "test")) {
246 lastfield = SUBUNIT_TEST;
247 } else if (!strcmp(p, "failure")) {
248 lastfield = SUBUNIT_FAILURE;
249 } else if (!strcmp(p, "success")) {
250 lastfield = SUBUNIT_SUCCESS;
251 } else if (!strcmp(p, "skip")) {
252 lastfield = SUBUNIT_SKIP;
253 } else {
254 torture_comment(context, "Invalid subunit field `%s'\n", p);
255 continue;
258 p = q+1;
260 name = talloc_strdup(context, p+1);
262 q = strrchr(p, '[');
263 if (q != NULL) {
264 *q = '\0';
265 comment = talloc_strdup(context, "");
266 } else {
267 run_subunit_message(context, lastfield, name, NULL);
268 talloc_free(name);
269 name = NULL;
274 offset += size-(p-buffer);
275 memcpy(buffer, p, offset);
278 if (waitpid(pid, &status, 0) == -1) {
279 torture_result(context, TORTURE_ERROR, "waitpid(%d) failed\n", pid);
280 return false;
283 if (WEXITSTATUS(status) != 0) {
284 torture_result(context, TORTURE_ERROR, "failed with status %d\n", WEXITSTATUS(status));
285 return false;
288 if (name != NULL) {
289 torture_result(context, TORTURE_ERROR, "Interrupted during %s\n", name);
290 return false;
293 return true;