source: mainline/uspace/lib/pcut/src/os/unix.c@ 01579ad

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 01579ad was 01579ad, checked in by Vojtech Horky <vojtechhorky@…>, 11 years ago

Start work on PCUT integration

PCUT is a simple library for (hopefully) easier unit testing.
See https://github.com/vhotspur/pcut for more details.

  • Property mode set to 100644
File size: 5.2 KB
RevLine 
[01579ad]1/*
2 * Copyright (c) 2013 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * 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.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file
30 *
31 * Unix-specific functions for test execution via the fork() system call.
32 */
33
34#include <stdlib.h>
35#include <unistd.h>
36#include <sys/types.h>
37#include <errno.h>
38#include <assert.h>
39#include <sys/wait.h>
40#include <stdio.h>
41#include <string.h>
42#include "../internal.h"
43
44/** Maximum size of stdout we are able to capture. */
45#define OUTPUT_BUFFER_SIZE 8192
46
47/** Buffer for assertion and other error messages. */
48static char error_message_buffer[OUTPUT_BUFFER_SIZE];
49
50/** Buffer for stdout from the test. */
51static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
52
53/** Prepare for a new test. */
54static void before_test_start(pcut_item_t *test) {
55 pcut_report_test_start(test);
56
57 memset(error_message_buffer, 0, OUTPUT_BUFFER_SIZE);
58 memset(extra_output_buffer, 0, OUTPUT_BUFFER_SIZE);
59}
60
61/** Read full buffer from given file descriptor.
62 *
63 * This function exists to overcome the possibility that read() may
64 * not fill the full length of the provided buffer even when EOF is
65 * not reached.
66 *
67 * @param fd Opened file descriptor.
68 * @param buffer Buffer to store data into.
69 * @param buffer_size Size of the @p buffer in bytes.
70 * @return Number of actually read bytes.
71 */
72static size_t read_all(int fd, char *buffer, size_t buffer_size) {
73 ssize_t actually_read;
74 char *buffer_start = buffer;
75 do {
76 actually_read = read(fd, buffer, buffer_size);
77 if (actually_read > 0) {
78 buffer += actually_read;
79 buffer_size -= actually_read;
80 if (buffer_size == 0) {
81 break;
82 }
83 }
84 } while (actually_read > 0);
85 if (buffer_start != buffer) {
86 if (*(buffer - 1) == 10) {
87 *(buffer - 1) = 0;
88 buffer--;
89 }
90 }
91 return buffer - buffer_start;
92}
93
94/** Convert program exit code to test outcome.
95 *
96 * @param status Status value from the wait() function.
97 * @return Test outcome code.
98 */
99static int convert_wait_status_to_outcome(int status) {
100 if (WIFEXITED(status)) {
101 if (WEXITSTATUS(status) != 0) {
102 return TEST_OUTCOME_FAIL;
103 } else {
104 return TEST_OUTCOME_PASS;
105 }
106 }
107
108 if (WIFSIGNALED(status)) {
109 return TEST_OUTCOME_ERROR;
110 }
111
112 return status;
113}
114
115/** Run the test in a forked environment and report the result.
116 *
117 * @param self_path Ignored.
118 * @param test Test to be run.
119 */
120void pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
121 PCUT_UNUSED(self_path);
122
123 before_test_start(test);
124
125 int link_stdout[2], link_stderr[2];
126 pid_t pid;
127
128 int rc = pipe(link_stdout);
129 if (rc == -1) {
130 snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
131 "pipe() failed: %s.", strerror(rc));
132 pcut_report_test_done(test, TEST_OUTCOME_ERROR, error_message_buffer, NULL, NULL);
133 return;
134 }
135 rc = pipe(link_stderr);
136 if (rc == -1) {
137 snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
138 "pipe() failed: %s.", strerror(rc));
139 pcut_report_test_done(test, TEST_OUTCOME_ERROR, error_message_buffer, NULL, NULL);
140 return;
141 }
142
143 pid = fork();
144 if (pid == (pid_t)-1) {
145 snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
146 "fork() failed: %s.", strerror(rc));
147 rc = TEST_OUTCOME_ERROR;
148 goto leave_close_pipes;
149 }
150
151 if (pid == 0) {
152 /* We are the child. */
153 dup2(link_stdout[1], STDOUT_FILENO);
154 close(link_stdout[0]);
155 dup2(link_stderr[1], STDERR_FILENO);
156 close(link_stderr[0]);
157
158 rc = pcut_run_test_forked(test);
159
160 exit(rc);
161 }
162
163 close(link_stdout[1]);
164 close(link_stderr[1]);
165
166 size_t stderr_size = read_all(link_stderr[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1);
167 read_all(link_stdout[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1 - stderr_size);
168
169 int status;
170 wait(&status);
171
172 rc = convert_wait_status_to_outcome(status);
173
174 goto leave_close_parent_pipe;
175
176leave_close_pipes:
177 close(link_stdout[1]);
178 close(link_stderr[1]);
179leave_close_parent_pipe:
180 close(link_stdout[0]);
181 close(link_stderr[0]);
182
183 pcut_report_test_done_unparsed(test, rc, extra_output_buffer, OUTPUT_BUFFER_SIZE);
184}
Note: See TracBrowser for help on using the repository browser.