1 // Copyright 2013 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 "store/backend.hpp" 30 31 #include <fstream> 32 #include <map> 33 34 #include <atf-c++.hpp> 35 36 #include "engine/action.hpp" 37 #include "engine/context.hpp" 38 #include "engine/test_case.hpp" 39 #include "engine/test_program.hpp" 40 #include "engine/test_result.hpp" 41 #include "store/backend.hpp" 42 #include "store/transaction.hpp" 43 #include "utils/format/macros.hpp" 44 #include "utils/fs/path.hpp" 45 #include "utils/logging/operations.hpp" 46 #include "utils/sqlite/database.hpp" 47 #include "utils/stream.hpp" 48 #include "utils/units.hpp" 49 50 namespace datetime = utils::datetime; 51 namespace fs = utils::fs; 52 namespace logging = utils::logging; 53 namespace sqlite = utils::sqlite; 54 namespace units = utils::units; 55 56 57 /// Executes an SQL script within a database. 58 /// 59 /// \param db Database in which to run the script. 60 /// \param path Path to the data file. 61 static void 62 exec_db_file(sqlite::database& db, const fs::path& path) 63 { 64 std::ifstream input(path.c_str()); 65 if (!input) 66 ATF_FAIL(F("Failed to open %s") % path); 67 db.exec(utils::read_stream(input)); 68 } 69 70 71 /// Validates the contents of the action with identifier 1. 72 /// 73 /// \param transaction An open read transaction in the backend. 74 static void 75 check_action_1(store::transaction& transaction) 76 { 77 const fs::path root("/some/root"); 78 std::map< std::string, std::string > environment; 79 const engine::context context_1(root, environment); 80 81 const engine::action action_1(context_1); 82 83 ATF_REQUIRE_EQ(action_1, transaction.get_action(1)); 84 85 store::results_iterator iter = transaction.get_action_results(1); 86 ATF_REQUIRE(!iter); 87 } 88 89 90 /// Validates the contents of the action with identifier 2. 91 /// 92 /// \param transaction An open read transaction in the backend. 93 static void 94 check_action_2(store::transaction& transaction) 95 { 96 const fs::path root("/test/suite/root"); 97 std::map< std::string, std::string > environment; 98 environment["HOME"] = "/home/test"; 99 environment["PATH"] = "/bin:/usr/bin"; 100 const engine::context context_2(root, environment); 101 102 const engine::action action_2(context_2); 103 104 ATF_REQUIRE_EQ(action_2, transaction.get_action(2)); 105 106 engine::test_program test_program_1( 107 "plain", fs::path("foo_test"), fs::path("/test/suite/root"), 108 "suite-name", engine::metadata_builder().build()); 109 { 110 const engine::test_case_ptr test_case_1(new engine::test_case( 111 "plain", test_program_1, "main", 112 engine::metadata_builder().build())); 113 engine::test_cases_vector test_cases; 114 test_cases.push_back(test_case_1); 115 test_program_1.set_test_cases(test_cases); 116 } 117 const engine::test_result result_1(engine::test_result::passed); 118 119 engine::test_program test_program_2( 120 "plain", fs::path("subdir/another_test"), fs::path("/test/suite/root"), 121 "subsuite-name", engine::metadata_builder() 122 .set_timeout(datetime::delta(10, 0)).build()); 123 { 124 const engine::test_case_ptr test_case_2(new engine::test_case( 125 "plain", test_program_2, "main", engine::metadata_builder() 126 .set_timeout(datetime::delta(10, 0)).build())); 127 engine::test_cases_vector test_cases; 128 test_cases.push_back(test_case_2); 129 test_program_2.set_test_cases(test_cases); 130 } 131 const engine::test_result result_2(engine::test_result::failed, 132 "Exited with code 1"); 133 134 engine::test_program test_program_3( 135 "plain", fs::path("subdir/bar_test"), fs::path("/test/suite/root"), 136 "subsuite-name", engine::metadata_builder().build()); 137 { 138 const engine::test_case_ptr test_case_3(new engine::test_case( 139 "plain", test_program_3, "main", 140 engine::metadata_builder().build())); 141 engine::test_cases_vector test_cases; 142 test_cases.push_back(test_case_3); 143 test_program_3.set_test_cases(test_cases); 144 } 145 const engine::test_result result_3(engine::test_result::broken, 146 "Received signal 1"); 147 148 engine::test_program test_program_4( 149 "plain", fs::path("top_test"), fs::path("/test/suite/root"), 150 "suite-name", engine::metadata_builder().build()); 151 { 152 const engine::test_case_ptr test_case_4(new engine::test_case( 153 "plain", test_program_4, "main", 154 engine::metadata_builder().build())); 155 engine::test_cases_vector test_cases; 156 test_cases.push_back(test_case_4); 157 test_program_4.set_test_cases(test_cases); 158 } 159 const engine::test_result result_4(engine::test_result::expected_failure, 160 "Known bug"); 161 162 engine::test_program test_program_5( 163 "plain", fs::path("last_test"), fs::path("/test/suite/root"), 164 "suite-name", engine::metadata_builder().build()); 165 { 166 const engine::test_case_ptr test_case_5(new engine::test_case( 167 "plain", test_program_5, "main", 168 engine::metadata_builder().build())); 169 engine::test_cases_vector test_cases; 170 test_cases.push_back(test_case_5); 171 test_program_5.set_test_cases(test_cases); 172 } 173 const engine::test_result result_5(engine::test_result::skipped, 174 "Does not apply"); 175 176 store::results_iterator iter = transaction.get_action_results(2); 177 ATF_REQUIRE(iter); 178 ATF_REQUIRE_EQ(test_program_1, *iter.test_program()); 179 ATF_REQUIRE_EQ("main", iter.test_case_name()); 180 ATF_REQUIRE_EQ(result_1, iter.result()); 181 ATF_REQUIRE(iter.stdout_contents().empty()); 182 ATF_REQUIRE(iter.stderr_contents().empty()); 183 ATF_REQUIRE_EQ(datetime::delta(10, 500), iter.duration()); 184 185 ++iter; 186 ATF_REQUIRE(iter); 187 ATF_REQUIRE_EQ(test_program_5, *iter.test_program()); 188 ATF_REQUIRE_EQ("main", iter.test_case_name()); 189 ATF_REQUIRE_EQ(result_5, iter.result()); 190 ATF_REQUIRE(iter.stdout_contents().empty()); 191 ATF_REQUIRE(iter.stderr_contents().empty()); 192 ATF_REQUIRE_EQ(datetime::delta(6, 0), iter.duration()); 193 194 ++iter; 195 ATF_REQUIRE(iter); 196 ATF_REQUIRE_EQ(test_program_2, *iter.test_program()); 197 ATF_REQUIRE_EQ("main", iter.test_case_name()); 198 ATF_REQUIRE_EQ(result_2, iter.result()); 199 ATF_REQUIRE_EQ("Test stdout", iter.stdout_contents()); 200 ATF_REQUIRE_EQ("Test stderr", iter.stderr_contents()); 201 ATF_REQUIRE_EQ(datetime::delta(0, 898821), iter.duration()); 202 203 ++iter; 204 ATF_REQUIRE(iter); 205 ATF_REQUIRE_EQ(test_program_3, *iter.test_program()); 206 ATF_REQUIRE_EQ("main", iter.test_case_name()); 207 ATF_REQUIRE_EQ(result_3, iter.result()); 208 ATF_REQUIRE(iter.stdout_contents().empty()); 209 ATF_REQUIRE(iter.stderr_contents().empty()); 210 ATF_REQUIRE_EQ(datetime::delta(7, 481932), iter.duration()); 211 212 ++iter; 213 ATF_REQUIRE(iter); 214 ATF_REQUIRE_EQ(test_program_4, *iter.test_program()); 215 ATF_REQUIRE_EQ("main", iter.test_case_name()); 216 ATF_REQUIRE_EQ(result_4, iter.result()); 217 ATF_REQUIRE(iter.stdout_contents().empty()); 218 ATF_REQUIRE(iter.stderr_contents().empty()); 219 ATF_REQUIRE_EQ(datetime::delta(0, 20000), iter.duration()); 220 221 ++iter; 222 ATF_REQUIRE(!iter); 223 } 224 225 226 /// Validates the contents of the action with identifier 3. 227 /// 228 /// \param transaction An open read transaction in the backend. 229 static void 230 check_action_3(store::transaction& transaction) 231 { 232 const fs::path root("/usr/tests"); 233 std::map< std::string, std::string > environment; 234 environment["PATH"] = "/bin:/usr/bin"; 235 const engine::context context_3(root, environment); 236 237 const engine::action action_3(context_3); 238 239 ATF_REQUIRE_EQ(action_3, transaction.get_action(3)); 240 241 engine::test_program test_program_6( 242 "atf", fs::path("complex_test"), fs::path("/usr/tests"), 243 "suite-name", engine::metadata_builder().build()); 244 { 245 const engine::test_case_ptr test_case_6(new engine::test_case( 246 "atf", test_program_6, "this_passes", 247 engine::metadata_builder().build())); 248 const engine::test_case_ptr test_case_7(new engine::test_case( 249 "atf", test_program_6, "this_fails", 250 engine::metadata_builder() 251 .set_description("Test description") 252 .set_has_cleanup(true) 253 .set_required_memory(units::bytes(128)) 254 .set_required_user("root").build())); 255 const engine::test_case_ptr test_case_8(new engine::test_case( 256 "atf", test_program_6, "this_skips", 257 engine::metadata_builder() 258 .add_allowed_architecture("powerpc") 259 .add_allowed_architecture("x86_64") 260 .add_allowed_platform("amd64") 261 .add_allowed_platform("macppc") 262 .add_required_config("X-foo") 263 .add_required_config("unprivileged_user") 264 .add_required_file(fs::path("/the/data/file")) 265 .add_required_program(fs::path("/bin/ls")) 266 .add_required_program(fs::path("cp")) 267 .set_description("Test explanation") 268 .set_has_cleanup(true) 269 .set_required_memory(units::bytes(512)) 270 .set_required_user("unprivileged") 271 .set_timeout(datetime::delta(600, 0)) 272 .build())); 273 engine::test_cases_vector test_cases; 274 test_cases.push_back(test_case_6); 275 test_cases.push_back(test_case_7); 276 test_cases.push_back(test_case_8); 277 test_program_6.set_test_cases(test_cases); 278 } 279 const engine::test_result result_6(engine::test_result::passed); 280 const engine::test_result result_7(engine::test_result::failed, 281 "Some reason"); 282 const engine::test_result result_8(engine::test_result::skipped, 283 "Another reason"); 284 285 engine::test_program test_program_7( 286 "atf", fs::path("simple_test"), fs::path("/usr/tests"), 287 "subsuite-name", engine::metadata_builder().build()); 288 { 289 const engine::test_case_ptr test_case_9(new engine::test_case( 290 "atf", test_program_7, "main", 291 engine::metadata_builder() 292 .set_description("More text") 293 .set_has_cleanup(true) 294 .set_required_memory(units::bytes(128)) 295 .set_required_user("unprivileged") 296 .build())); 297 engine::test_cases_vector test_cases; 298 test_cases.push_back(test_case_9); 299 test_program_7.set_test_cases(test_cases); 300 } 301 const engine::test_result result_9(engine::test_result::failed, 302 "Exited with code 1"); 303 304 store::results_iterator iter = transaction.get_action_results(3); 305 ATF_REQUIRE(iter); 306 ATF_REQUIRE_EQ(test_program_6, *iter.test_program()); 307 ATF_REQUIRE_EQ("this_fails", iter.test_case_name()); 308 ATF_REQUIRE_EQ(result_7, iter.result()); 309 ATF_REQUIRE(iter.stdout_contents().empty()); 310 ATF_REQUIRE(iter.stderr_contents().empty()); 311 ATF_REQUIRE_EQ(datetime::delta(1, 897182), iter.duration()); 312 313 ++iter; 314 ATF_REQUIRE(iter); 315 ATF_REQUIRE_EQ(test_program_6, *iter.test_program()); 316 ATF_REQUIRE_EQ("this_passes", iter.test_case_name()); 317 ATF_REQUIRE_EQ(result_6, iter.result()); 318 ATF_REQUIRE(iter.stdout_contents().empty()); 319 ATF_REQUIRE(iter.stderr_contents().empty()); 320 ATF_REQUIRE_EQ(datetime::delta(6, 0), iter.duration()); 321 322 ++iter; 323 ATF_REQUIRE(iter); 324 ATF_REQUIRE_EQ(test_program_6, *iter.test_program()); 325 ATF_REQUIRE_EQ("this_skips", iter.test_case_name()); 326 ATF_REQUIRE_EQ(result_8, iter.result()); 327 ATF_REQUIRE_EQ("Another stdout", iter.stdout_contents()); 328 ATF_REQUIRE(iter.stderr_contents().empty()); 329 ATF_REQUIRE_EQ(datetime::delta(0, 817987), iter.duration()); 330 331 ++iter; 332 ATF_REQUIRE(iter); 333 ATF_REQUIRE_EQ(test_program_7, *iter.test_program()); 334 ATF_REQUIRE_EQ("main", iter.test_case_name()); 335 ATF_REQUIRE_EQ(result_9, iter.result()); 336 ATF_REQUIRE(iter.stdout_contents().empty()); 337 ATF_REQUIRE_EQ("Another stderr", iter.stderr_contents()); 338 ATF_REQUIRE_EQ(datetime::delta(9, 961700), iter.duration()); 339 340 ++iter; 341 ATF_REQUIRE(!iter); 342 } 343 344 345 /// Validates the contents of the action with identifier 4. 346 /// 347 /// \param transaction An open read transaction in the backend. 348 static void 349 check_action_4(store::transaction& transaction) 350 { 351 const fs::path root("/usr/tests"); 352 std::map< std::string, std::string > environment; 353 environment["LANG"] = "C"; 354 environment["PATH"] = "/bin:/usr/bin"; 355 environment["TERM"] = "xterm"; 356 const engine::context context_4(root, environment); 357 358 const engine::action action_4(context_4); 359 360 ATF_REQUIRE_EQ(action_4, transaction.get_action(4)); 361 362 engine::test_program test_program_8( 363 "plain", fs::path("subdir/another_test"), fs::path("/usr/tests"), 364 "subsuite-name", engine::metadata_builder() 365 .set_timeout(datetime::delta(10, 0)).build()); 366 { 367 const engine::test_case_ptr test_case_10(new engine::test_case( 368 "plain", test_program_8, "main", 369 engine::metadata_builder() 370 .set_timeout(datetime::delta(10, 0)).build())); 371 engine::test_cases_vector test_cases; 372 test_cases.push_back(test_case_10); 373 test_program_8.set_test_cases(test_cases); 374 } 375 const engine::test_result result_10(engine::test_result::failed, 376 "Exit failure"); 377 378 engine::test_program test_program_9( 379 "atf", fs::path("complex_test"), fs::path("/usr/tests"), 380 "suite-name", engine::metadata_builder().build()); 381 { 382 const engine::test_case_ptr test_case_11(new engine::test_case( 383 "atf", test_program_9, "this_passes", 384 engine::metadata_builder().build())); 385 const engine::test_case_ptr test_case_12(new engine::test_case( 386 "atf", test_program_9, "this_fails", 387 engine::metadata_builder() 388 .set_description("Test description") 389 .set_required_user("root") 390 .build())); 391 engine::test_cases_vector test_cases; 392 test_cases.push_back(test_case_11); 393 test_cases.push_back(test_case_12); 394 test_program_9.set_test_cases(test_cases); 395 } 396 const engine::test_result result_11(engine::test_result::passed); 397 const engine::test_result result_12(engine::test_result::failed, 398 "Some reason"); 399 400 store::results_iterator iter = transaction.get_action_results(4); 401 ATF_REQUIRE(iter); 402 ATF_REQUIRE_EQ(test_program_9, *iter.test_program()); 403 ATF_REQUIRE_EQ("this_fails", iter.test_case_name()); 404 ATF_REQUIRE_EQ(result_12, iter.result()); 405 ATF_REQUIRE(iter.stdout_contents().empty()); 406 ATF_REQUIRE(iter.stderr_contents().empty()); 407 ATF_REQUIRE_EQ(datetime::delta(1, 905000), iter.duration()); 408 409 ++iter; 410 ATF_REQUIRE(iter); 411 ATF_REQUIRE_EQ(test_program_9, *iter.test_program()); 412 ATF_REQUIRE_EQ("this_passes", iter.test_case_name()); 413 ATF_REQUIRE_EQ(result_11, iter.result()); 414 ATF_REQUIRE(iter.stdout_contents().empty()); 415 ATF_REQUIRE(iter.stderr_contents().empty()); 416 ATF_REQUIRE_EQ(datetime::delta(0, 500000), iter.duration()); 417 418 ++iter; 419 ATF_REQUIRE(iter); 420 ATF_REQUIRE_EQ(test_program_8, *iter.test_program()); 421 ATF_REQUIRE_EQ("main", iter.test_case_name()); 422 ATF_REQUIRE_EQ(result_10, iter.result()); 423 ATF_REQUIRE_EQ("Test stdout", iter.stdout_contents()); 424 ATF_REQUIRE_EQ("Test stderr", iter.stderr_contents()); 425 ATF_REQUIRE_EQ(datetime::delta(1, 0), iter.duration()); 426 427 ++iter; 428 ATF_REQUIRE(!iter); 429 } 430 431 432 /// Validates the contents of an open database agains good known values. 433 /// 434 /// \param transaction An open read-only backend. 435 static void 436 check_data(store::backend& backend) 437 { 438 store::transaction transaction = backend.start(); 439 check_action_1(transaction); 440 check_action_2(transaction); 441 check_action_3(transaction); 442 check_action_4(transaction); 443 } 444 445 446 ATF_TEST_CASE(current_schema); 447 ATF_TEST_CASE_HEAD(current_schema) 448 { 449 logging::set_inmemory(); 450 const std::string required_files = 451 store::detail::schema_file().str() 452 + " " + (fs::path(get_config_var("srcdir")) / "testdata_v2.sql").str(); 453 set_md_var("require.files", required_files); 454 } 455 ATF_TEST_CASE_BODY(current_schema) 456 { 457 const fs::path testpath("test.db"); 458 459 sqlite::database db = sqlite::database::open( 460 testpath, sqlite::open_readwrite | sqlite::open_create); 461 exec_db_file(db, store::detail::schema_file()); 462 exec_db_file(db, fs::path(get_config_var("srcdir")) / "testdata_v2.sql"); 463 db.close(); 464 465 store::backend backend = store::backend::open_ro(testpath); 466 check_data(backend); 467 } 468 469 470 ATF_TEST_CASE(migrate_schema__v1_to_v2); 471 ATF_TEST_CASE_HEAD(migrate_schema__v1_to_v2) 472 { 473 logging::set_inmemory(); 474 const std::string required_files = 475 store::detail::migration_file(1, 2).str() 476 + " " + (fs::path(get_config_var("srcdir")) / "schema_v1.sql").str() 477 + " " + (fs::path(get_config_var("srcdir")) / "testdata_v1.sql").str(); 478 set_md_var("require.files", required_files); 479 } 480 ATF_TEST_CASE_BODY(migrate_schema__v1_to_v2) 481 { 482 const fs::path testpath("test.db"); 483 484 sqlite::database db = sqlite::database::open( 485 testpath, sqlite::open_readwrite | sqlite::open_create); 486 exec_db_file(db, fs::path(get_config_var("srcdir")) / "schema_v1.sql"); 487 exec_db_file(db, fs::path(get_config_var("srcdir")) / "testdata_v1.sql"); 488 db.close(); 489 490 store::migrate_schema(fs::path("test.db")); 491 492 store::backend backend = store::backend::open_ro(testpath); 493 check_data(backend); 494 } 495 496 497 ATF_INIT_TEST_CASES(tcs) 498 { 499 ATF_ADD_TEST_CASE(tcs, current_schema); 500 501 ATF_ADD_TEST_CASE(tcs, migrate_schema__v1_to_v2); 502 } 503