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