1 1.1 jmmv // Copyright 2010 Google Inc. 2 1.1 jmmv // All rights reserved. 3 1.1 jmmv // 4 1.1 jmmv // Redistribution and use in source and binary forms, with or without 5 1.1 jmmv // modification, are permitted provided that the following conditions are 6 1.1 jmmv // met: 7 1.1 jmmv // 8 1.1 jmmv // * Redistributions of source code must retain the above copyright 9 1.1 jmmv // notice, this list of conditions and the following disclaimer. 10 1.1 jmmv // * Redistributions in binary form must reproduce the above copyright 11 1.1 jmmv // notice, this list of conditions and the following disclaimer in the 12 1.1 jmmv // documentation and/or other materials provided with the distribution. 13 1.1 jmmv // * Neither the name of Google Inc. nor the names of its contributors 14 1.1 jmmv // may be used to endorse or promote products derived from this software 15 1.1 jmmv // without specific prior written permission. 16 1.1 jmmv // 17 1.1 jmmv // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 1.1 jmmv // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 1.1 jmmv // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 1.1 jmmv // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 1.1 jmmv // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 1.1 jmmv // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 1.1 jmmv // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 jmmv // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 jmmv // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 jmmv // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 1.1 jmmv // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 jmmv 29 1.1 jmmv #include "engine/test_program.hpp" 30 1.1 jmmv 31 1.1.1.2 jmmv extern "C" { 32 1.1.1.2 jmmv #include <sys/stat.h> 33 1.1.1.2 jmmv 34 1.1.1.2 jmmv #include <signal.h> 35 1.1.1.2 jmmv } 36 1.1.1.2 jmmv 37 1.1 jmmv #include <sstream> 38 1.1 jmmv 39 1.1 jmmv #include <atf-c++.hpp> 40 1.1 jmmv 41 1.1 jmmv #include "engine/exceptions.hpp" 42 1.1.1.2 jmmv #include "engine/test_result.hpp" 43 1.1.1.2 jmmv #include "utils/env.hpp" 44 1.1.1.2 jmmv #include "utils/format/macros.hpp" 45 1.1 jmmv #include "utils/fs/operations.hpp" 46 1.1 jmmv #include "utils/fs/path.hpp" 47 1.1.1.2 jmmv #include "utils/optional.ipp" 48 1.1 jmmv 49 1.1 jmmv namespace fs = utils::fs; 50 1.1 jmmv 51 1.1 jmmv 52 1.1.1.2 jmmv namespace { 53 1.1.1.2 jmmv 54 1.1.1.2 jmmv 55 1.1.1.2 jmmv /// Creates a mock tester that receives a signal. 56 1.1.1.2 jmmv /// 57 1.1.1.2 jmmv /// \param term_sig Signal to deliver to the tester. If the tester does not 58 1.1.1.2 jmmv /// exit due to this reason, it exits with an arbitrary non-zero code. 59 1.1.1.2 jmmv static void 60 1.1.1.2 jmmv create_mock_tester_signal(const int term_sig) 61 1.1.1.2 jmmv { 62 1.1.1.2 jmmv const std::string tester_name = "kyua-mock-tester"; 63 1.1.1.2 jmmv 64 1.1.1.2 jmmv atf::utils::create_file( 65 1.1.1.2 jmmv tester_name, 66 1.1.1.2 jmmv F("#! /bin/sh\n" 67 1.1.1.2 jmmv "kill -%s $$\n" 68 1.1.1.2 jmmv "exit 0\n") % term_sig); 69 1.1.1.2 jmmv ATF_REQUIRE(::chmod(tester_name.c_str(), 0755) != -1); 70 1.1.1.2 jmmv 71 1.1.1.2 jmmv utils::setenv("KYUA_TESTERSDIR", fs::current_path().str()); 72 1.1.1.2 jmmv } 73 1.1.1.2 jmmv 74 1.1.1.2 jmmv 75 1.1.1.2 jmmv } // anonymous namespace 76 1.1.1.2 jmmv 77 1.1.1.2 jmmv 78 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(ctor_and_getters); 79 1.1 jmmv ATF_TEST_CASE_BODY(ctor_and_getters) 80 1.1 jmmv { 81 1.1 jmmv const engine::metadata md = engine::metadata_builder() 82 1.1 jmmv .add_custom("foo", "bar") 83 1.1 jmmv .build(); 84 1.1 jmmv const engine::test_program test_program( 85 1.1 jmmv "mock", fs::path("binary"), fs::path("root"), "suite-name", md); 86 1.1 jmmv ATF_REQUIRE_EQ("mock", test_program.interface_name()); 87 1.1 jmmv ATF_REQUIRE_EQ(fs::path("binary"), test_program.relative_path()); 88 1.1 jmmv ATF_REQUIRE_EQ(fs::current_path() / "root/binary", 89 1.1 jmmv test_program.absolute_path()); 90 1.1 jmmv ATF_REQUIRE_EQ(fs::path("root"), test_program.root()); 91 1.1 jmmv ATF_REQUIRE_EQ("suite-name", test_program.test_suite_name()); 92 1.1 jmmv ATF_REQUIRE_EQ(md, test_program.get_metadata()); 93 1.1 jmmv } 94 1.1 jmmv 95 1.1 jmmv 96 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(find__ok); 97 1.1 jmmv ATF_TEST_CASE_BODY(find__ok) 98 1.1 jmmv { 99 1.1 jmmv const engine::test_program test_program( 100 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite-name", 101 1.1 jmmv engine::metadata_builder().build()); 102 1.1 jmmv const engine::test_case_ptr test_case = test_program.find("main"); 103 1.1 jmmv ATF_REQUIRE_EQ(fs::path("non-existent"), 104 1.1 jmmv test_case->container_test_program().relative_path()); 105 1.1 jmmv ATF_REQUIRE_EQ("main", test_case->name()); 106 1.1 jmmv } 107 1.1 jmmv 108 1.1 jmmv 109 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(find__missing); 110 1.1 jmmv ATF_TEST_CASE_BODY(find__missing) 111 1.1 jmmv { 112 1.1 jmmv const engine::test_program test_program( 113 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite-name", 114 1.1 jmmv engine::metadata_builder().build()); 115 1.1 jmmv ATF_REQUIRE_THROW_RE(engine::not_found_error, 116 1.1 jmmv "case.*abc.*program.*non-existent", 117 1.1 jmmv test_program.find("abc")); 118 1.1 jmmv } 119 1.1 jmmv 120 1.1 jmmv 121 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(test_cases__get); 122 1.1 jmmv ATF_TEST_CASE_BODY(test_cases__get) 123 1.1 jmmv { 124 1.1 jmmv const engine::test_program test_program( 125 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite-name", 126 1.1 jmmv engine::metadata_builder().build()); 127 1.1 jmmv const engine::test_cases_vector& test_cases = test_program.test_cases(); 128 1.1 jmmv ATF_REQUIRE_EQ(1, test_cases.size()); 129 1.1 jmmv ATF_REQUIRE_EQ(fs::path("non-existent"), 130 1.1 jmmv test_cases[0]->container_test_program().relative_path()); 131 1.1 jmmv ATF_REQUIRE_EQ("main", test_cases[0]->name()); 132 1.1 jmmv } 133 1.1 jmmv 134 1.1 jmmv 135 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(test_cases__some); 136 1.1 jmmv ATF_TEST_CASE_BODY(test_cases__some) 137 1.1 jmmv { 138 1.1 jmmv engine::test_program test_program( 139 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite-name", 140 1.1 jmmv engine::metadata_builder().build()); 141 1.1 jmmv 142 1.1 jmmv engine::test_cases_vector exp_test_cases; 143 1.1 jmmv const engine::test_case test_case("plain", test_program, "main", 144 1.1 jmmv engine::metadata_builder().build()); 145 1.1 jmmv exp_test_cases.push_back(engine::test_case_ptr( 146 1.1 jmmv new engine::test_case(test_case))); 147 1.1 jmmv test_program.set_test_cases(exp_test_cases); 148 1.1 jmmv 149 1.1 jmmv ATF_REQUIRE_EQ(exp_test_cases, test_program.test_cases()); 150 1.1 jmmv } 151 1.1 jmmv 152 1.1 jmmv 153 1.1.1.2 jmmv ATF_TEST_CASE_WITHOUT_HEAD(test_cases__tester_fails); 154 1.1.1.2 jmmv ATF_TEST_CASE_BODY(test_cases__tester_fails) 155 1.1.1.2 jmmv { 156 1.1.1.2 jmmv engine::test_program test_program( 157 1.1.1.2 jmmv "mock", fs::path("non-existent"), fs::path("."), "suite-name", 158 1.1.1.2 jmmv engine::metadata_builder().build()); 159 1.1.1.2 jmmv create_mock_tester_signal(SIGSEGV); 160 1.1.1.2 jmmv 161 1.1.1.2 jmmv const engine::test_cases_vector& test_cases = test_program.test_cases(); 162 1.1.1.2 jmmv ATF_REQUIRE_EQ(1, test_cases.size()); 163 1.1.1.2 jmmv 164 1.1.1.2 jmmv const engine::test_case_ptr& test_case = test_cases[0]; 165 1.1.1.2 jmmv ATF_REQUIRE_EQ("__test_cases_list__", test_case->name()); 166 1.1.1.2 jmmv 167 1.1.1.2 jmmv ATF_REQUIRE(test_case->fake_result()); 168 1.1.1.2 jmmv const engine::test_result result = test_case->fake_result().get(); 169 1.1.1.2 jmmv ATF_REQUIRE(engine::test_result::broken == result.type()); 170 1.1.1.2 jmmv ATF_REQUIRE_MATCH("Tester did not exit cleanly", result.reason()); 171 1.1.1.2 jmmv } 172 1.1.1.2 jmmv 173 1.1.1.2 jmmv 174 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__copy); 175 1.1 jmmv ATF_TEST_CASE_BODY(operators_eq_and_ne__copy) 176 1.1 jmmv { 177 1.1 jmmv const engine::test_program tp1( 178 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite-name", 179 1.1 jmmv engine::metadata_builder().build()); 180 1.1 jmmv const engine::test_program tp2 = tp1; 181 1.1 jmmv ATF_REQUIRE( tp1 == tp2); 182 1.1 jmmv ATF_REQUIRE(!(tp1 != tp2)); 183 1.1 jmmv } 184 1.1 jmmv 185 1.1 jmmv 186 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__not_copy); 187 1.1 jmmv ATF_TEST_CASE_BODY(operators_eq_and_ne__not_copy) 188 1.1 jmmv { 189 1.1 jmmv const std::string base_interface("plain"); 190 1.1 jmmv const fs::path base_relative_path("the/test/program"); 191 1.1 jmmv const fs::path base_root("/the/root"); 192 1.1 jmmv const std::string base_test_suite("suite-name"); 193 1.1 jmmv const engine::metadata base_metadata = engine::metadata_builder() 194 1.1 jmmv .add_custom("X-foo", "bar") 195 1.1 jmmv .build(); 196 1.1 jmmv 197 1.1 jmmv engine::test_program base_tp( 198 1.1 jmmv base_interface, base_relative_path, base_root, base_test_suite, 199 1.1 jmmv base_metadata); 200 1.1 jmmv 201 1.1 jmmv engine::test_cases_vector base_tcs; 202 1.1 jmmv { 203 1.1 jmmv const engine::test_case tc1("plain", base_tp, "main", 204 1.1 jmmv engine::metadata_builder().build()); 205 1.1 jmmv base_tcs.push_back(engine::test_case_ptr(new engine::test_case(tc1))); 206 1.1 jmmv } 207 1.1 jmmv base_tp.set_test_cases(base_tcs); 208 1.1 jmmv 209 1.1 jmmv // Construct with all same values. 210 1.1 jmmv { 211 1.1 jmmv engine::test_program other_tp( 212 1.1 jmmv base_interface, base_relative_path, base_root, base_test_suite, 213 1.1 jmmv base_metadata); 214 1.1 jmmv 215 1.1 jmmv engine::test_cases_vector other_tcs; 216 1.1 jmmv { 217 1.1 jmmv const engine::test_case tc1("plain", other_tp, "main", 218 1.1 jmmv engine::metadata_builder().build()); 219 1.1 jmmv other_tcs.push_back(engine::test_case_ptr( 220 1.1 jmmv new engine::test_case(tc1))); 221 1.1 jmmv } 222 1.1 jmmv other_tp.set_test_cases(other_tcs); 223 1.1 jmmv 224 1.1 jmmv ATF_REQUIRE( base_tp == other_tp); 225 1.1 jmmv ATF_REQUIRE(!(base_tp != other_tp)); 226 1.1 jmmv } 227 1.1 jmmv 228 1.1 jmmv // Different interface. 229 1.1 jmmv { 230 1.1 jmmv engine::test_program other_tp( 231 1.1 jmmv "atf", base_relative_path, base_root, base_test_suite, 232 1.1 jmmv base_metadata); 233 1.1 jmmv other_tp.set_test_cases(base_tcs); 234 1.1 jmmv 235 1.1 jmmv ATF_REQUIRE(!(base_tp == other_tp)); 236 1.1 jmmv ATF_REQUIRE( base_tp != other_tp); 237 1.1 jmmv } 238 1.1 jmmv 239 1.1 jmmv // Different relative path. 240 1.1 jmmv { 241 1.1 jmmv engine::test_program other_tp( 242 1.1 jmmv base_interface, fs::path("a/b/c"), base_root, base_test_suite, 243 1.1 jmmv base_metadata); 244 1.1 jmmv other_tp.set_test_cases(base_tcs); 245 1.1 jmmv 246 1.1 jmmv ATF_REQUIRE(!(base_tp == other_tp)); 247 1.1 jmmv ATF_REQUIRE( base_tp != other_tp); 248 1.1 jmmv } 249 1.1 jmmv 250 1.1 jmmv // Different root. 251 1.1 jmmv { 252 1.1 jmmv engine::test_program other_tp( 253 1.1 jmmv base_interface, base_relative_path, fs::path("."), base_test_suite, 254 1.1 jmmv base_metadata); 255 1.1 jmmv other_tp.set_test_cases(base_tcs); 256 1.1 jmmv 257 1.1 jmmv ATF_REQUIRE(!(base_tp == other_tp)); 258 1.1 jmmv ATF_REQUIRE( base_tp != other_tp); 259 1.1 jmmv } 260 1.1 jmmv 261 1.1 jmmv // Different test suite. 262 1.1 jmmv { 263 1.1 jmmv engine::test_program other_tp( 264 1.1 jmmv base_interface, base_relative_path, base_root, "different-suite", 265 1.1 jmmv base_metadata); 266 1.1 jmmv other_tp.set_test_cases(base_tcs); 267 1.1 jmmv 268 1.1 jmmv ATF_REQUIRE(!(base_tp == other_tp)); 269 1.1 jmmv ATF_REQUIRE( base_tp != other_tp); 270 1.1 jmmv } 271 1.1 jmmv 272 1.1 jmmv // Different metadata. 273 1.1 jmmv { 274 1.1 jmmv engine::test_program other_tp( 275 1.1 jmmv base_interface, base_relative_path, base_root, base_test_suite, 276 1.1 jmmv engine::metadata_builder().build()); 277 1.1 jmmv other_tp.set_test_cases(base_tcs); 278 1.1 jmmv 279 1.1 jmmv ATF_REQUIRE(!(base_tp == other_tp)); 280 1.1 jmmv ATF_REQUIRE( base_tp != other_tp); 281 1.1 jmmv } 282 1.1 jmmv 283 1.1 jmmv // Different test cases. 284 1.1 jmmv { 285 1.1 jmmv engine::test_program other_tp( 286 1.1 jmmv base_interface, base_relative_path, base_root, base_test_suite, 287 1.1 jmmv base_metadata); 288 1.1 jmmv 289 1.1 jmmv engine::test_cases_vector other_tcs; 290 1.1 jmmv { 291 1.1 jmmv const engine::test_case tc1("atf", base_tp, "foo", 292 1.1 jmmv engine::metadata_builder().build()); 293 1.1 jmmv other_tcs.push_back(engine::test_case_ptr( 294 1.1 jmmv new engine::test_case(tc1))); 295 1.1 jmmv } 296 1.1 jmmv other_tp.set_test_cases(other_tcs); 297 1.1 jmmv 298 1.1 jmmv ATF_REQUIRE(!(base_tp == other_tp)); 299 1.1 jmmv ATF_REQUIRE( base_tp != other_tp); 300 1.1 jmmv } 301 1.1 jmmv } 302 1.1 jmmv 303 1.1 jmmv 304 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(output__no_test_cases); 305 1.1 jmmv ATF_TEST_CASE_BODY(output__no_test_cases) 306 1.1 jmmv { 307 1.1 jmmv engine::test_program tp( 308 1.1 jmmv "plain", fs::path("binary/path"), fs::path("/the/root"), "suite-name", 309 1.1 jmmv engine::metadata_builder().add_allowed_architecture("a").build()); 310 1.1 jmmv tp.set_test_cases(engine::test_cases_vector()); 311 1.1 jmmv 312 1.1 jmmv std::ostringstream str; 313 1.1 jmmv str << tp; 314 1.1 jmmv ATF_REQUIRE_EQ( 315 1.1 jmmv "test_program{interface='plain', binary='binary/path', " 316 1.1 jmmv "root='/the/root', test_suite='suite-name', " 317 1.1 jmmv "metadata=metadata{allowed_architectures='a', allowed_platforms='', " 318 1.1 jmmv "description='', has_cleanup='false', " 319 1.1 jmmv "required_configs='', required_files='', required_memory='0', " 320 1.1 jmmv "required_programs='', required_user='', timeout='300'}, " 321 1.1 jmmv "test_cases=[]}", 322 1.1 jmmv str.str()); 323 1.1 jmmv } 324 1.1 jmmv 325 1.1 jmmv 326 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(output__some_test_cases); 327 1.1 jmmv ATF_TEST_CASE_BODY(output__some_test_cases) 328 1.1 jmmv { 329 1.1 jmmv engine::test_program tp( 330 1.1 jmmv "plain", fs::path("binary/path"), fs::path("/the/root"), "suite-name", 331 1.1 jmmv engine::metadata_builder().add_allowed_architecture("a").build()); 332 1.1 jmmv 333 1.1 jmmv const engine::test_case_ptr tc1(new engine::test_case( 334 1.1 jmmv "plain", tp, "the-name", engine::metadata_builder() 335 1.1 jmmv .add_allowed_platform("foo").add_custom("X-bar", "baz").build())); 336 1.1 jmmv const engine::test_case_ptr tc2(new engine::test_case( 337 1.1 jmmv "plain", tp, "another-name", engine::metadata_builder().build())); 338 1.1 jmmv engine::test_cases_vector tcs; 339 1.1 jmmv tcs.push_back(tc1); 340 1.1 jmmv tcs.push_back(tc2); 341 1.1 jmmv tp.set_test_cases(tcs); 342 1.1 jmmv 343 1.1 jmmv std::ostringstream str; 344 1.1 jmmv str << tp; 345 1.1 jmmv ATF_REQUIRE_EQ( 346 1.1 jmmv "test_program{interface='plain', binary='binary/path', " 347 1.1 jmmv "root='/the/root', test_suite='suite-name', " 348 1.1 jmmv "metadata=metadata{allowed_architectures='a', allowed_platforms='', " 349 1.1 jmmv "description='', has_cleanup='false', " 350 1.1 jmmv "required_configs='', required_files='', required_memory='0', " 351 1.1 jmmv "required_programs='', required_user='', timeout='300'}, " 352 1.1 jmmv "test_cases=[" 353 1.1 jmmv "test_case{interface='plain', name='the-name', " 354 1.1 jmmv "metadata=metadata{allowed_architectures='', allowed_platforms='foo', " 355 1.1 jmmv "custom.X-bar='baz', description='', has_cleanup='false', " 356 1.1 jmmv "required_configs='', required_files='', required_memory='0', " 357 1.1 jmmv "required_programs='', required_user='', timeout='300'}}, " 358 1.1 jmmv "test_case{interface='plain', name='another-name', " 359 1.1 jmmv "metadata=metadata{allowed_architectures='', allowed_platforms='', " 360 1.1 jmmv "description='', has_cleanup='false', " 361 1.1 jmmv "required_configs='', required_files='', required_memory='0', " 362 1.1 jmmv "required_programs='', required_user='', timeout='300'}}]}", 363 1.1 jmmv str.str()); 364 1.1 jmmv } 365 1.1 jmmv 366 1.1 jmmv 367 1.1 jmmv ATF_INIT_TEST_CASES(tcs) 368 1.1 jmmv { 369 1.1 jmmv // TODO(jmmv): These tests have ceased to be realistic with the move to 370 1.1 jmmv // TestersDesign. We probably should have some (few!) integration tests for 371 1.1 jmmv // the various known testers... or, alternatively, provide a mock tester to 372 1.1 jmmv // run our tests with. 373 1.1 jmmv ATF_ADD_TEST_CASE(tcs, ctor_and_getters); 374 1.1 jmmv ATF_ADD_TEST_CASE(tcs, find__ok); 375 1.1 jmmv ATF_ADD_TEST_CASE(tcs, find__missing); 376 1.1 jmmv ATF_ADD_TEST_CASE(tcs, test_cases__get); 377 1.1 jmmv ATF_ADD_TEST_CASE(tcs, test_cases__some); 378 1.1.1.2 jmmv ATF_ADD_TEST_CASE(tcs, test_cases__tester_fails); 379 1.1 jmmv 380 1.1 jmmv ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__copy); 381 1.1 jmmv ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__not_copy); 382 1.1 jmmv 383 1.1 jmmv ATF_ADD_TEST_CASE(tcs, output__no_test_cases); 384 1.1 jmmv ATF_ADD_TEST_CASE(tcs, output__some_test_cases); 385 1.1 jmmv } 386