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 "engine/testers.hpp" 30 31 extern "C" { 32 #include <sys/stat.h> 33 } 34 35 #include <cstdlib> 36 37 #include <atf-c++.hpp> 38 39 #include "engine/exceptions.hpp" 40 #include "utils/datetime.hpp" 41 #include "utils/env.hpp" 42 #include "utils/format/macros.hpp" 43 #include "utils/fs/path.hpp" 44 #include "utils/fs/operations.hpp" 45 #include "utils/optional.ipp" 46 #include "utils/passwd.hpp" 47 48 namespace datetime = utils::datetime; 49 namespace fs = utils::fs; 50 namespace passwd = utils::passwd; 51 52 using utils::none; 53 using utils::optional; 54 55 56 namespace { 57 58 59 /// Creates a mock tester. 60 /// 61 /// The interface accepted by the tester is 'mock'. This tester outputs the 62 /// arguments passed to it and then prints a message to both the stdout and the 63 /// stderr. 64 /// 65 /// \param exit_status Code to exit with. 66 static void 67 create_mock_tester(const int exit_status) 68 { 69 atf::utils::create_file( 70 "kyua-mock-tester", 71 F("#! /bin/sh\n" 72 "while [ ${#} -gt 0 ]; do\n" 73 " echo \"Arg: ${1}\"\n" 74 " shift\n" 75 "done\n" 76 "echo 'tester output'\n" 77 "echo 'tester error' 1>&2\n" 78 "exit %s\n") % exit_status); 79 ATF_REQUIRE(::chmod("kyua-mock-tester", 0755) != -1); 80 81 utils::setenv("KYUA_TESTERSDIR", fs::current_path().str()); 82 } 83 84 85 } // anonymous namespace 86 87 88 ATF_TEST_CASE_WITHOUT_HEAD(tester__list__defaults); 89 ATF_TEST_CASE_BODY(tester__list__defaults) 90 { 91 create_mock_tester(EXIT_SUCCESS); 92 engine::tester tester("mock", none, none); 93 const std::string output = tester.list(fs::path("/foo/bar")); 94 95 const std::string exp_output = 96 "Arg: list\n" 97 "Arg: /foo/bar\n" 98 "tester output\n" 99 "tester error\n"; 100 ATF_REQUIRE_EQ(exp_output, output); 101 } 102 103 104 ATF_TEST_CASE_WITHOUT_HEAD(tester__list__explicit_common_args); 105 ATF_TEST_CASE_BODY(tester__list__explicit_common_args) 106 { 107 const passwd::user user("fake", 123, 456); 108 const datetime::delta timeout(15, 0); 109 110 create_mock_tester(EXIT_SUCCESS); 111 engine::tester tester("mock", utils::make_optional(user), 112 utils::make_optional(timeout)); 113 const std::string output = tester.list(fs::path("/another/program/1")); 114 115 const std::string exp_output = 116 "Arg: -u123\n" 117 "Arg: -g456\n" 118 "Arg: -t15\n" 119 "Arg: list\n" 120 "Arg: /another/program/1\n" 121 "tester output\n" 122 "tester error\n"; 123 ATF_REQUIRE_EQ(exp_output, output); 124 } 125 126 127 ATF_TEST_CASE_WITHOUT_HEAD(tester__list__unknown_interface); 128 ATF_TEST_CASE_BODY(tester__list__unknown_interface) 129 { 130 utils::setenv("KYUA_TESTERSDIR", "."); 131 engine::tester tester("non-existent", none, none); 132 ATF_REQUIRE_THROW_RE(engine::error, "Unknown interface non-existent", 133 tester.list(fs::path("does-not-matter"))); 134 } 135 136 137 ATF_TEST_CASE_WITHOUT_HEAD(tester__list__tester_fails); 138 ATF_TEST_CASE_BODY(tester__list__tester_fails) 139 { 140 create_mock_tester(EXIT_FAILURE); 141 engine::tester tester("mock", none, none); 142 ATF_REQUIRE_THROW_RE( 143 engine::error, 144 "Tester did not exit cleanly:.*tester output.*tester error", 145 tester.list(fs::path("does-not-matter"))); 146 } 147 148 149 ATF_TEST_CASE_WITHOUT_HEAD(tester__test__defaults); 150 ATF_TEST_CASE_BODY(tester__test__defaults) 151 { 152 std::map< std::string, std::string > vars; 153 154 create_mock_tester(EXIT_FAILURE); 155 engine::tester tester("mock", none, none); 156 tester.test(fs::path("/foo/bar"), "test-case", fs::path("/the/result/file"), 157 fs::path("tester.out"), fs::path("tester.err"), vars); 158 159 const std::string exp_output = 160 "Arg: test\n" 161 "Arg: /foo/bar\n" 162 "Arg: test-case\n" 163 "Arg: /the/result/file\n" 164 "tester output\n"; 165 const std::string exp_error = 166 "tester error\n"; 167 ATF_REQUIRE(atf::utils::compare_file("tester.out", exp_output)); 168 ATF_REQUIRE(atf::utils::compare_file("tester.err", exp_error)); 169 } 170 171 172 ATF_TEST_CASE_WITHOUT_HEAD(tester__test__explicit_common_args_and_vars); 173 ATF_TEST_CASE_BODY(tester__test__explicit_common_args_and_vars) 174 { 175 const passwd::user user("fake", 123, 456); 176 const datetime::delta timeout(15, 0); 177 178 std::map< std::string, std::string > vars; 179 vars["var1"] = "value1"; 180 vars["variable-2"] = "value with spaces"; 181 182 create_mock_tester(EXIT_SUCCESS); 183 engine::tester tester("mock", utils::make_optional(user), 184 utils::make_optional(timeout)); 185 tester.test(fs::path("/foo/bar"), "test-case", fs::path("/the/result/file"), 186 fs::path("tester.out"), fs::path("tester.err"), vars); 187 188 const std::string exp_output = 189 "Arg: -u123\n" 190 "Arg: -g456\n" 191 "Arg: -t15\n" 192 "Arg: test\n" 193 "Arg: -vvar1=value1\n" 194 "Arg: -vvariable-2=value with spaces\n" 195 "Arg: /foo/bar\n" 196 "Arg: test-case\n" 197 "Arg: /the/result/file\n" 198 "tester output\n"; 199 const std::string exp_error = 200 "tester error\n"; 201 ATF_REQUIRE(atf::utils::compare_file("tester.out", exp_output)); 202 ATF_REQUIRE(atf::utils::compare_file("tester.err", exp_error)); 203 } 204 205 206 ATF_TEST_CASE_WITHOUT_HEAD(tester__test__unknown_interface); 207 ATF_TEST_CASE_BODY(tester__test__unknown_interface) 208 { 209 const std::map< std::string, std::string > vars; 210 211 utils::setenv("KYUA_TESTERSDIR", "."); 212 engine::tester tester("non-existent", none, none); 213 ATF_REQUIRE_THROW_RE(engine::error, "Unknown interface non-existent", 214 tester.test(fs::path("foo"), "bar", fs::path("baz"), 215 fs::path("out"), fs::path("err"), vars)); 216 } 217 218 219 ATF_TEST_CASE_WITHOUT_HEAD(tester__test__tester_fails); 220 ATF_TEST_CASE_BODY(tester__test__tester_fails) 221 { 222 const std::map< std::string, std::string > vars; 223 224 create_mock_tester(2); 225 engine::tester tester("mock", none, none); 226 ATF_REQUIRE_THROW_RE( 227 engine::error, 228 "Tester failed with code 2; this is a bug", 229 tester.test(fs::path("foo"), "bar", fs::path("baz"), 230 fs::path("out"), fs::path("err"), vars)); 231 } 232 233 234 ATF_TEST_CASE_WITHOUT_HEAD(tester_path__default); 235 ATF_TEST_CASE_BODY(tester_path__default) 236 { 237 ATF_REQUIRE(atf::utils::file_exists(engine::tester_path("atf").str())); 238 ATF_REQUIRE(atf::utils::file_exists(engine::tester_path("plain").str())); 239 } 240 241 242 ATF_TEST_CASE_WITHOUT_HEAD(tester_path__custom); 243 ATF_TEST_CASE_BODY(tester_path__custom) 244 { 245 fs::mkdir(fs::path("testers"), 0755); 246 atf::utils::create_file("testers/kyua-mock-1-tester", "Not a binary"); 247 atf::utils::create_file("testers/kyua-mock-2-tester", "Not a binary"); 248 utils::setenv("KYUA_TESTERSDIR", (fs::current_path() / "testers").str()); 249 250 const fs::path mock1 = engine::tester_path("mock-1"); 251 ATF_REQUIRE(mock1.is_absolute()); 252 ATF_REQUIRE(atf::utils::file_exists(mock1.str())); 253 254 const fs::path mock2 = engine::tester_path("mock-2"); 255 ATF_REQUIRE(mock2.is_absolute()); 256 ATF_REQUIRE(atf::utils::file_exists(mock2.str())); 257 258 ATF_REQUIRE_THROW_RE(engine::error, "Unknown interface mock-3", 259 engine::tester_path("mock-3")); 260 } 261 262 263 ATF_TEST_CASE_WITHOUT_HEAD(tester_path__cached); 264 ATF_TEST_CASE_BODY(tester_path__cached) 265 { 266 fs::mkdir(fs::path("testers"), 0755); 267 atf::utils::create_file("testers/kyua-mock-tester", "Not a binary"); 268 utils::setenv("KYUA_TESTERSDIR", (fs::current_path() / "testers").str()); 269 270 const fs::path mock = engine::tester_path("mock"); 271 ATF_REQUIRE(atf::utils::file_exists(mock.str())); 272 ATF_REQUIRE(::unlink(mock.c_str()) != -1); 273 ATF_REQUIRE(!atf::utils::file_exists(mock.str())); 274 ATF_REQUIRE_EQ(mock, engine::tester_path("mock")); 275 } 276 277 278 ATF_TEST_CASE_WITHOUT_HEAD(tester_path__empty); 279 ATF_TEST_CASE_BODY(tester_path__empty) 280 { 281 fs::mkdir(fs::path("testers"), 0755); 282 atf::utils::create_file("testers/kyua--tester", "Not a binary"); 283 utils::setenv("KYUA_TESTERSDIR", (fs::current_path() / "testers").str()); 284 285 ATF_REQUIRE_THROW_RE(engine::error, "Unknown interface ", 286 engine::tester_path("")); 287 } 288 289 290 ATF_TEST_CASE_WITHOUT_HEAD(tester_path__missing); 291 ATF_TEST_CASE_BODY(tester_path__missing) 292 { 293 utils::setenv("KYUA_TESTERSDIR", fs::current_path().str()); 294 ATF_REQUIRE_THROW_RE(engine::error, "Unknown interface plain", 295 engine::tester_path("plain")); 296 } 297 298 299 ATF_INIT_TEST_CASES(tcs) 300 { 301 ATF_ADD_TEST_CASE(tcs, tester__list__defaults); 302 ATF_ADD_TEST_CASE(tcs, tester__list__explicit_common_args); 303 ATF_ADD_TEST_CASE(tcs, tester__list__unknown_interface); 304 ATF_ADD_TEST_CASE(tcs, tester__list__tester_fails); 305 306 ATF_ADD_TEST_CASE(tcs, tester__test__defaults); 307 ATF_ADD_TEST_CASE(tcs, tester__test__explicit_common_args_and_vars); 308 ATF_ADD_TEST_CASE(tcs, tester__test__unknown_interface); 309 ATF_ADD_TEST_CASE(tcs, tester__test__tester_fails); 310 311 ATF_ADD_TEST_CASE(tcs, tester_path__default); 312 ATF_ADD_TEST_CASE(tcs, tester_path__custom); 313 ATF_ADD_TEST_CASE(tcs, tester_path__cached); 314 ATF_ADD_TEST_CASE(tcs, tester_path__empty); 315 ATF_ADD_TEST_CASE(tcs, tester_path__missing); 316 } 317