1 // Copyright 2015 The Kyua Authors. 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 extern "C" { 30 #include <sys/stat.h> 31 32 #include <unistd.h> 33 34 extern char** environ; 35 } 36 37 #include <cstdlib> 38 #include <cstring> 39 #include <fstream> 40 #include <iostream> 41 42 #include "utils/env.hpp" 43 #include "utils/format/containers.ipp" 44 #include "utils/format/macros.hpp" 45 #include "utils/fs/path.hpp" 46 #include "utils/optional.ipp" 47 #include "utils/test_utils.ipp" 48 49 namespace fs = utils::fs; 50 51 52 namespace { 53 54 55 /// Logs an error message and exits the test with an error code. 56 /// 57 /// \param str The error message to log. 58 static void 59 fail(const std::string& str) 60 { 61 std::cerr << str << '\n'; 62 std::exit(EXIT_FAILURE); 63 } 64 65 66 /// A test scenario that validates the TEST_ENV_* variables. 67 static void 68 test_check_configuration_variables(void) 69 { 70 std::set< std::string > vars; 71 char** iter; 72 for (iter = environ; *iter != NULL; ++iter) { 73 if (std::strstr(*iter, "TEST_ENV_") == *iter) { 74 vars.insert(*iter); 75 } 76 } 77 78 std::set< std::string > exp_vars; 79 exp_vars.insert("TEST_ENV_first=some value"); 80 exp_vars.insert("TEST_ENV_second=some other value"); 81 if (vars == exp_vars) { 82 std::cout << "1..1\n" 83 << "ok 1\n"; 84 } else { 85 std::cout << "1..1\n" 86 << "not ok 1\n" 87 << F(" Expected: %s\nFound: %s\n") % exp_vars % vars; 88 } 89 } 90 91 92 /// A test scenario that crashes. 93 static void 94 test_crash(void) 95 { 96 utils::abort_without_coredump(); 97 } 98 99 100 /// A test scenario that reports some tests as failed. 101 static void 102 test_fail(void) 103 { 104 std::cout << "1..5\n" 105 << "ok 1 - This is good!\n" 106 << "not ok 2\n" 107 << "ok 3 - TODO Consider this as passed\n" 108 << "ok 4\n" 109 << "not ok 5\n"; 110 } 111 112 113 /// A test scenario that passes. 114 static void 115 test_pass(void) 116 { 117 std::cout << "1..4\n" 118 << "ok 1 - This is good!\n" 119 << "non-result data\n" 120 << "ok 2 - SKIP Consider this as passed\n" 121 << "ok 3 - TODO Consider this as passed\n" 122 << "ok 4\n"; 123 } 124 125 126 /// A test scenario that passes but then exits with non-zero. 127 static void 128 test_pass_but_exit_failure(void) 129 { 130 std::cout << "1..2\n" 131 << "ok 1\n" 132 << "ok 2\n"; 133 std::exit(70); 134 } 135 136 137 /// A test scenario that times out. 138 /// 139 /// Note that the timeout is defined in the Kyuafile, as the TAP interface has 140 /// no means for test programs to specify this by themselves. 141 static void 142 test_timeout(void) 143 { 144 std::cout << "1..2\n" 145 << "ok 1\n"; 146 147 ::sleep(10); 148 const fs::path control_dir = fs::path(utils::getenv("CONTROL_DIR").get()); 149 std::ofstream file((control_dir / "cookie").c_str()); 150 if (!file) 151 fail("Failed to create the control cookie"); 152 file.close(); 153 } 154 155 156 } // anonymous namespace 157 158 159 /// Entry point to the test program. 160 /// 161 /// The caller can select which test scenario to run by modifying the program's 162 /// basename on disk (either by a copy or by a hard link). 163 /// 164 /// \todo It may be worth to split this binary into separate, smaller binaries, 165 /// one for every "test scenario". We use this program as a dispatcher for 166 /// different "main"s, the only reason being to keep the amount of helper test 167 /// programs to a minimum. However, putting this each function in its own 168 /// binary could simplify many other things. 169 /// 170 /// \param argc The number of CLI arguments. 171 /// \param argv The CLI arguments themselves. These are not used because 172 /// Kyua will not pass any arguments to the plain test program. 173 int 174 main(int argc, char** argv) 175 { 176 if (argc != 1) { 177 std::cerr << "No arguments allowed; select the test scenario with the " 178 "program's basename\n"; 179 return EXIT_FAILURE; 180 } 181 182 const std::string& test_scenario = fs::path(argv[0]).leaf_name(); 183 184 if (test_scenario == "check_configuration_variables") 185 test_check_configuration_variables(); 186 else if (test_scenario == "crash") 187 test_crash(); 188 else if (test_scenario == "fail") 189 test_fail(); 190 else if (test_scenario == "pass") 191 test_pass(); 192 else if (test_scenario == "pass_but_exit_failure") 193 test_pass_but_exit_failure(); 194 else if (test_scenario == "timeout") 195 test_timeout(); 196 else { 197 std::cerr << "Unknown test scenario\n"; 198 return EXIT_FAILURE; 199 } 200 201 return EXIT_SUCCESS; 202 } 203