xref: /minix3/external/bsd/kyua-testers/dist/plain_main.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 //   notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 //   notice, this list of conditions and the following disclaimer in the
12 //   documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 //   may be used to endorse or promote products derived from this software
15 //   without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #include <sys/wait.h>
30 
31 #include <assert.h>
32 #include <err.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "cli.h"
38 #include "defs.h"
39 #include "error.h"
40 #include "result.h"
41 #include "run.h"
42 #include "stacktrace.h"
43 
44 
45 /// Template for the creation of the temporary work directories.
46 #define WORKDIR_TEMPLATE "kyua.plain-tester.XXXXXX"
47 
48 
49 /// Name of the fake test case exposed by the program.
50 const char* const fake_test_case_name = "main";
51 
52 
53 /// Converts the exit status of a program to a result.
54 ///
55 /// \param status Exit status of the test program, as returned by waitpid().
56 /// \param timed_out Whether the test program timed out or not.
57 /// \param result_file Path to the result file to create.
58 /// \param [out] success Set to true if the test program returned with a
59 ///     successful condition.
60 ///
61 /// \return An error if something went wrong.
62 static kyua_error_t
status_to_result(int status,const bool timed_out,const char * result_file,bool * success)63 status_to_result(int status, const bool timed_out, const char* result_file,
64                  bool* success)
65 {
66     if (timed_out) {
67         *success = false;
68         return kyua_result_write(result_file, KYUA_RESULT_BROKEN,
69                                  "Test case timed out");
70     }
71 
72     if (WIFEXITED(status)) {
73         if (WEXITSTATUS(status) == EXIT_SUCCESS) {
74             *success = true;
75             return kyua_result_write(result_file, KYUA_RESULT_PASSED, NULL);
76         } else {
77             *success = false;
78             return kyua_result_write(result_file, KYUA_RESULT_FAILED,
79                                      "Returned non-success exit status %d",
80                                      WEXITSTATUS(status));
81         }
82     } else {
83         assert(WIFSIGNALED(status));
84         *success = false;
85         return kyua_result_write(result_file, KYUA_RESULT_BROKEN,
86                                  "Received signal %d", WTERMSIG(status));
87     }
88 }
89 
90 
91 /// Lists the test cases in a test program.
92 ///
93 /// \param unused_test_program Path to the test program for which to list the
94 ///     test cases.  Should be absolute.
95 /// \param unused_run_params Execution parameters to configure the test process.
96 ///
97 /// \return An error if the listing fails; OK otherwise.
98 static kyua_error_t
list_test_cases(const char * KYUA_DEFS_UNUSED_PARAM (test_program),const kyua_run_params_t * KYUA_DEFS_UNUSED_PARAM (run_params))99 list_test_cases(const char* KYUA_DEFS_UNUSED_PARAM(test_program),
100                 const kyua_run_params_t* KYUA_DEFS_UNUSED_PARAM(run_params))
101 {
102     printf("test_case{name='%s'}\n", fake_test_case_name);
103     return kyua_error_ok();
104 }
105 
106 
107 /// Runs a single test cases of a test program.
108 ///
109 /// \param test_program Path to the test program for which to list the test
110 ///     cases.  Should be absolute.
111 /// \param test_case Name of the test case to run.
112 /// \param result_file Path to the file to which to write the result of the
113 ///     test.  Should be absolute.
114 /// \param user_variables Array of name=value pairs that describe the user
115 ///     configuration variables for the test case.
116 /// \param run_params Execution parameters to configure the test process.
117 /// \param [out] success Set to true if the test case reported a valid exit
118 ///     condition (like "passed" or "skipped"); false otherwise.  This is
119 ///     only updated if the method returns OK.
120 ///
121 /// \return An error if the listing fails; OK otherwise.
122 static kyua_error_t
run_test_case(const char * test_program,const char * test_case,const char * result_file,const char * const user_variables[],const kyua_run_params_t * run_params,bool * success)123 run_test_case(const char* test_program, const char* test_case,
124               const char* result_file, const char* const user_variables[],
125               const kyua_run_params_t* run_params,
126               bool* success)
127 {
128     kyua_error_t error;
129 
130     if (strcmp(test_case, fake_test_case_name) != 0) {
131         error = kyua_generic_error_new("Unknown test case '%s'", test_case);
132         goto out;
133     }
134 
135     const char* const* iter;
136     for (iter = user_variables; *iter != NULL; ++iter) {
137         warnx("Configuration variables not supported; ignoring '%s'", *iter);
138     }
139 
140     char *work_directory;
141     error = kyua_run_work_directory_enter(WORKDIR_TEMPLATE,
142                                           run_params->unprivileged_user,
143                                           run_params->unprivileged_group,
144                                           &work_directory);
145     if (kyua_error_is_set(error))
146         goto out;
147     kyua_run_params_t real_run_params = *run_params;
148     real_run_params.work_directory = work_directory;
149 
150     pid_t pid;
151     error = kyua_run_fork(&real_run_params, &pid);
152     if (!kyua_error_is_set(error) && pid == 0) {
153         const char* const program_args[] = { test_program, NULL };
154         kyua_run_exec(test_program, program_args);
155     }
156     assert(pid != -1 && pid != 0);
157     if (kyua_error_is_set(error))
158         goto out_work_directory;
159 
160     int status; bool timed_out;
161     error = kyua_run_wait(pid, &status, &timed_out);
162     if (kyua_error_is_set(error))
163         goto out_work_directory;
164 
165     if (WIFSIGNALED(status) && WCOREDUMP(status)) {
166         kyua_stacktrace_dump(test_program, pid, run_params, stderr);
167     }
168 
169     error = status_to_result(status, timed_out, result_file, success);
170 
171 out_work_directory:
172     error = kyua_error_subsume(error,
173         kyua_run_work_directory_leave(&work_directory));
174 out:
175     return error;
176 }
177 
178 
179 /// Definition of the tester.
180 static kyua_cli_tester_t plain_tester = {
181     .list_test_cases = list_test_cases,
182     .run_test_case = run_test_case,
183 };
184 
185 
186 /// Tester entry point.
187 ///
188 /// \param argc Number of command line arguments.
189 /// \param argv NULL-terminated array of command line arguments.
190 ///
191 /// \return An exit code.
192 int
main(const int argc,char * const * const argv)193 main(const int argc, char* const* const argv)
194 {
195     return kyua_cli_main(argc, argv, &plain_tester);
196 }
197