1// Copyright 2011 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 29extern "C" { 30#include <sys/stat.h> 31 32#include <unistd.h> 33} 34 35#include <cstdlib> 36#include <fstream> 37#include <iostream> 38#include <sstream> 39 40#include "utils/defs.hpp" 41#include "utils/env.hpp" 42#include "utils/fs/operations.hpp" 43#include "utils/fs/path.hpp" 44#include "utils/optional.ipp" 45 46namespace fs = utils::fs; 47 48using utils::optional; 49 50 51namespace { 52 53 54/// Logs an error message and exits the test with an error code. 55/// 56/// \param str The error message to log. 57static void 58fail(const char* str) 59{ 60 std::cerr << str << '\n'; 61 std::exit(EXIT_FAILURE); 62} 63 64 65/// A test case that crashes. 66static void 67test_crash(void) 68{ 69 std::abort(); 70} 71 72 73/// A test case that exits with a non-zero exit code, and not 1. 74static void 75test_fail(void) 76{ 77 std::exit(8); 78} 79 80 81/// A test case that passes. 82static void 83test_pass(void) 84{ 85} 86 87 88/// A test case that spawns a subchild that gets stuck. 89/// 90/// This test case is used by the caller to validate that the whole process tree 91/// is terminated when the test case is killed. 92static void 93test_spawn_blocking_child(void) 94{ 95 pid_t pid = ::fork(); 96 if (pid == -1) 97 fail("Cannot fork subprocess"); 98 else if (pid == 0) { 99 for (;;) 100 ::pause(); 101 } else { 102 const fs::path name = fs::path(utils::getenv("CONTROL_DIR").get()) / 103 "pid"; 104 std::ofstream pidfile(name.c_str()); 105 if (!pidfile) 106 fail("Failed to create the pidfile"); 107 pidfile << pid; 108 pidfile.close(); 109 } 110} 111 112 113/// A test case that times out. 114/// 115/// Note that the timeout is defined in the Kyuafile, as the plain interface has 116/// no means for test programs to specify this by themselves. 117static void 118test_timeout(void) 119{ 120 ::sleep(10); 121 const fs::path control_dir = fs::path(utils::getenv("CONTROL_DIR").get()); 122 std::ofstream file((control_dir / "cookie").c_str()); 123 if (!file) 124 fail("Failed to create the control cookie"); 125 file.close(); 126} 127 128 129/// A test case that performs basic checks on the runtime environment. 130/// 131/// If the runtime environment does not look clean (according to the rules in 132/// the Kyua runtime properties), the test fails. 133static void 134test_validate_isolation(void) 135{ 136 if (utils::getenv("HOME").get() == "fake-value") 137 fail("HOME not reset"); 138 if (utils::getenv("LANG")) 139 fail("LANG not unset"); 140} 141 142 143} // anonymous namespace 144 145 146/// Entry point to the test program. 147/// 148/// The caller can select which test case to run by defining the TEST_CASE 149/// environment variable. This is not "standard", in the sense this is not a 150/// generic property of the plain test case interface. 151/// 152/// \todo It may be worth to split this binary into separate, smaller binaries, 153/// one for every "test case". We use this program as a dispatcher for 154/// different "main"s, the only reason being to keep the amount of helper test 155/// programs to a minimum. However, putting this each function in its own 156/// binary could simplify many other things. 157/// 158/// \param argc The number of CLI arguments. 159/// \param unused_argv The CLI arguments themselves. These are not used because 160/// Kyua will not pass any arguments to the plain test program. 161int 162main(int argc, char** UTILS_UNUSED_PARAM(argv)) 163{ 164 if (argc != 1) { 165 std::cerr << "No arguments allowed; select the test case with the " 166 "TEST_CASE variable"; 167 return EXIT_FAILURE; 168 } 169 170 const optional< std::string > test_case_env = utils::getenv("TEST_CASE"); 171 if (!test_case_env) { 172 std::cerr << "TEST_CASE not defined"; 173 return EXIT_FAILURE; 174 } 175 const std::string& test_case = test_case_env.get(); 176 177 if (test_case == "crash") 178 test_crash(); 179 else if (test_case == "fail") 180 test_fail(); 181 else if (test_case == "pass") 182 test_pass(); 183 else if (test_case == "spawn_blocking_child") 184 test_spawn_blocking_child(); 185 else if (test_case == "timeout") 186 test_timeout(); 187 else if (test_case == "validate_isolation") 188 test_validate_isolation(); 189 else { 190 std::cerr << "Unknown test case"; 191 return EXIT_FAILURE; 192 } 193 194 return EXIT_SUCCESS; 195} 196