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 /// \file common_inttest.h 30 /// Common integration tests for the tester binaries. 31 32 #if defined(KYUA_COMMON_INTTEST_H) 33 # error "common_inttest.h can only be defined once" 34 #endif 35 /// Include guard. 36 #define KYUA_COMMON_INTTEST_H 37 38 #if !defined(INTERFACE) 39 # error "Must define INTERFACE to the name of the tester interface" 40 #endif 41 42 #include <err.h> 43 #include <stdarg.h> 44 #include <stdbool.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 48 #include <atf-c.h> 49 50 #include "cli.h" // For the EXIT_* constants only. 51 #include "defs.h" 52 53 54 /// Path to the installed testers. 55 static const char* default_testersdir = TESTERSDIR; 56 57 58 /// Returns the name of the current tester. 59 #define TESTER_BIN "kyua-" INTERFACE "-tester" 60 61 62 /// Returns the path to the helpers. 63 /// 64 /// \param tc Pointer to the caller test case, to obtain the srcdir property. 65 /// 66 /// \return A dynamically-allocated string; must be released with free(3). 67 static char* 68 helpers_path(const atf_tc_t* tc) 69 { 70 const char* srcdir = atf_tc_get_config_var(tc, "srcdir"); 71 const char* name = INTERFACE "_helpers"; 72 73 const size_t length = strlen(srcdir) + 1 + strlen(name) + 1; 74 char* buffer = (char*)malloc(length); 75 (void)snprintf(buffer, length, "%s/%s", srcdir, name); 76 return buffer; 77 } 78 79 80 /// Returns the path to the tester. 81 /// 82 /// \return A dynamically-allocated string; must be released with free(3). 83 static char* 84 tester_path(void) 85 { 86 const char* testersdir = getenv("TESTERSDIR"); 87 if (testersdir == NULL) 88 testersdir = default_testersdir; 89 const char* name = TESTER_BIN; 90 91 const size_t length = strlen(testersdir) + 1 + strlen(name) + 1; 92 char* buffer = (char*)malloc(length); 93 ATF_REQUIRE(buffer != NULL); 94 (void)snprintf(buffer, length, "%s/%s", testersdir, name); 95 return buffer; 96 } 97 98 99 /// Initializes the test case metadata and the helpers. 100 /// 101 /// \param [in,out] tc The test case in which to set the property. 102 /// \param uses_helpers Whether the test uses the helpers or not. 103 static void 104 setup(atf_tc_t* tc, const bool uses_helpers) 105 { 106 char* tester = tester_path(); 107 if (uses_helpers) { 108 char* helpers = helpers_path(tc); 109 atf_tc_set_md_var(tc, "require.progs", "%s %s", tester, helpers); 110 free(helpers); 111 } else { 112 atf_tc_set_md_var(tc, "require.progs", "%s", tester); 113 } 114 free(tester); 115 } 116 117 118 static void execute(va_list ap) KYUA_DEFS_NORETURN; 119 120 121 /// Executes the tester with the given set of variable arguments. 122 /// 123 /// \param ap List of arguments to the tester. 124 static void 125 execute(va_list ap) 126 { 127 const char* args[16]; 128 129 const char** current_arg = &args[0]; 130 *current_arg = TESTER_BIN; 131 ++current_arg; 132 while ((*current_arg = va_arg(ap, const char*)) != NULL) 133 ++current_arg; 134 135 char* program = tester_path(); 136 (void)execv(program, KYUA_DEFS_UNCONST(args)); 137 free(program); 138 err(111, "Failed to execute %s", program); 139 } 140 141 142 /// Executes the tester and validates its output. 143 /// 144 /// \param expected_exit_status Expected exit status of the subprocess. 145 /// \param expected_stdout Expected contents of stdout. 146 /// \param expected_stderr Expected contents of stderr. 147 /// \param ... Arguments to the tester, not including the program name. 148 static void 149 check(const int expected_exit_status, const char* expected_stdout, 150 const char* expected_stderr, ...) 151 { 152 const pid_t pid = atf_utils_fork(); 153 if (pid == 0) { 154 va_list ap; 155 va_start(ap, expected_stderr); 156 execute(ap); 157 va_end(ap); 158 } else { 159 atf_utils_wait(pid, expected_exit_status, expected_stdout, 160 expected_stderr); 161 } 162 } 163 164 165 ATF_TC(top__missing_command); 166 ATF_TC_HEAD(top__missing_command, tc) { setup(tc, false); } 167 ATF_TC_BODY(top__missing_command, tc) 168 { 169 check(EXIT_USAGE_ERROR, "", TESTER_BIN": Must provide a command\n", 170 NULL); 171 } 172 173 174 ATF_TC(top__unknown_command); 175 ATF_TC_HEAD(top__unknown_command, tc) { setup(tc, false); } 176 ATF_TC_BODY(top__unknown_command, tc) 177 { 178 check(EXIT_USAGE_ERROR, "", TESTER_BIN": Unknown command 'foo'\n", 179 "foo", NULL); 180 } 181