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 29 #include "store/transaction.hpp" 30 31 #include <cstring> 32 #include <map> 33 #include <set> 34 #include <string> 35 36 #include <atf-c++.hpp> 37 38 #include "engine/action.hpp" 39 #include "engine/context.hpp" 40 #include "engine/test_result.hpp" 41 #include "store/backend.hpp" 42 #include "store/exceptions.hpp" 43 #include "utils/datetime.hpp" 44 #include "utils/fs/path.hpp" 45 #include "utils/logging/operations.hpp" 46 #include "utils/optional.ipp" 47 #include "utils/sqlite/database.hpp" 48 #include "utils/sqlite/exceptions.hpp" 49 #include "utils/sqlite/statement.ipp" 50 #include "utils/units.hpp" 51 52 namespace datetime = utils::datetime; 53 namespace fs = utils::fs; 54 namespace logging = utils::logging; 55 namespace sqlite = utils::sqlite; 56 namespace units = utils::units; 57 58 using utils::none; 59 using utils::optional; 60 61 62 namespace { 63 64 65 /// Performs a test for a working put_result 66 /// 67 /// \param result The result object to put. 68 /// \param result_type The textual name of the result to expect in the 69 /// database. 70 /// \param exp_reason The reason to expect in the database. This is separate 71 /// from the result parameter so that we can handle passed() here as well. 72 /// Just provide NULL in this case. 73 static void 74 do_put_result_ok_test(const engine::test_result& result, 75 const char* result_type, const char* exp_reason) 76 { 77 store::backend backend = store::backend::open_rw(fs::path("test.db")); 78 backend.database().exec("PRAGMA foreign_keys = OFF"); 79 store::transaction tx = backend.start(); 80 const datetime::timestamp start_time = datetime::timestamp::from_values( 81 2012, 01, 30, 22, 10, 00, 0); 82 const datetime::timestamp end_time = datetime::timestamp::from_values( 83 2012, 01, 30, 22, 15, 30, 123456); 84 tx.put_result(result, 312, start_time, end_time); 85 tx.commit(); 86 87 sqlite::statement stmt = backend.database().create_statement( 88 "SELECT test_case_id, result_type, result_reason " 89 "FROM test_results"); 90 91 ATF_REQUIRE(stmt.step()); 92 ATF_REQUIRE_EQ(312, stmt.column_int64(0)); 93 ATF_REQUIRE_EQ(result_type, stmt.column_text(1)); 94 if (exp_reason != NULL) 95 ATF_REQUIRE_EQ(exp_reason, stmt.column_text(2)); 96 else 97 ATF_REQUIRE(stmt.column_type(2) == sqlite::type_null); 98 ATF_REQUIRE(!stmt.step()); 99 } 100 101 102 } // anonymous namespace 103 104 105 ATF_TEST_CASE(commit__ok); 106 ATF_TEST_CASE_HEAD(commit__ok) 107 { 108 logging::set_inmemory(); 109 set_md_var("require.files", store::detail::schema_file().c_str()); 110 } 111 ATF_TEST_CASE_BODY(commit__ok) 112 { 113 store::backend backend = store::backend::open_rw(fs::path("test.db")); 114 store::transaction tx = backend.start(); 115 backend.database().exec("CREATE TABLE a (b INTEGER PRIMARY KEY)"); 116 backend.database().exec("SELECT * FROM a"); 117 tx.commit(); 118 backend.database().exec("SELECT * FROM a"); 119 } 120 121 122 ATF_TEST_CASE(commit__fail); 123 ATF_TEST_CASE_HEAD(commit__fail) 124 { 125 logging::set_inmemory(); 126 set_md_var("require.files", store::detail::schema_file().c_str()); 127 } 128 ATF_TEST_CASE_BODY(commit__fail) 129 { 130 store::backend backend = store::backend::open_rw(fs::path("test.db")); 131 const engine::context context(fs::path("/foo/bar"), 132 std::map< std::string, std::string >()); 133 { 134 store::transaction tx = backend.start(); 135 tx.put_context(context); 136 backend.database().exec( 137 "CREATE TABLE foo (" 138 "a REFERENCES contexts(context_id) DEFERRABLE INITIALLY DEFERRED)"); 139 backend.database().exec("INSERT INTO foo VALUES (912378472)"); 140 ATF_REQUIRE_THROW(store::error, tx.commit()); 141 } 142 // If the code attempts to maintain any state regarding the already-put 143 // objects and the commit does not clean up correctly, this would fail in 144 // some manner. 145 store::transaction tx = backend.start(); 146 tx.put_context(context); 147 tx.commit(); 148 } 149 150 151 ATF_TEST_CASE(rollback__ok); 152 ATF_TEST_CASE_HEAD(rollback__ok) 153 { 154 logging::set_inmemory(); 155 set_md_var("require.files", store::detail::schema_file().c_str()); 156 } 157 ATF_TEST_CASE_BODY(rollback__ok) 158 { 159 store::backend backend = store::backend::open_rw(fs::path("test.db")); 160 store::transaction tx = backend.start(); 161 backend.database().exec("CREATE TABLE a_table (b INTEGER PRIMARY KEY)"); 162 backend.database().exec("SELECT * FROM a_table"); 163 tx.rollback(); 164 ATF_REQUIRE_THROW_RE(sqlite::error, "a_table", 165 backend.database().exec("SELECT * FROM a_table")); 166 } 167 168 169 ATF_TEST_CASE(get_put_action__ok); 170 ATF_TEST_CASE_HEAD(get_put_action__ok) 171 { 172 logging::set_inmemory(); 173 set_md_var("require.files", store::detail::schema_file().c_str()); 174 } 175 ATF_TEST_CASE_BODY(get_put_action__ok) 176 { 177 store::backend backend = store::backend::open_rw(fs::path("test.db")); 178 const engine::context context1(fs::path("/foo/bar"), 179 std::map< std::string, std::string >()); 180 const engine::context context2(fs::path("/foo/baz"), 181 std::map< std::string, std::string >()); 182 const engine::action exp_action1(context1); 183 const engine::action exp_action2(context2); 184 const engine::action exp_action3(context1); 185 186 int64_t id1, id2, id3; 187 { 188 store::transaction tx = backend.start(); 189 const int64_t context1_id = tx.put_context(context1); 190 const int64_t context2_id = tx.put_context(context2); 191 id1 = tx.put_action(exp_action1, context1_id); 192 id3 = tx.put_action(exp_action3, context1_id); 193 id2 = tx.put_action(exp_action2, context2_id); 194 tx.commit(); 195 } 196 { 197 store::transaction tx = backend.start(); 198 const engine::action action1 = tx.get_action(id1); 199 const engine::action action2 = tx.get_action(id2); 200 const engine::action action3 = tx.get_action(id3); 201 tx.rollback(); 202 203 ATF_REQUIRE(exp_action1 == action1); 204 ATF_REQUIRE(exp_action2 == action2); 205 ATF_REQUIRE(exp_action3 == action3); 206 } 207 } 208 209 210 ATF_TEST_CASE(get_put_action__get_fail__missing); 211 ATF_TEST_CASE_HEAD(get_put_action__get_fail__missing) 212 { 213 logging::set_inmemory(); 214 set_md_var("require.files", store::detail::schema_file().c_str()); 215 } 216 ATF_TEST_CASE_BODY(get_put_action__get_fail__missing) 217 { 218 store::backend backend = store::backend::open_rw(fs::path("test.db")); 219 220 store::transaction tx = backend.start(); 221 ATF_REQUIRE_THROW_RE(store::error, "action 523: does not exist", 222 tx.get_action(523)); 223 } 224 225 226 ATF_TEST_CASE(get_put_action__get_fail__invalid_context); 227 ATF_TEST_CASE_HEAD(get_put_action__get_fail__invalid_context) 228 { 229 logging::set_inmemory(); 230 set_md_var("require.files", store::detail::schema_file().c_str()); 231 } 232 ATF_TEST_CASE_BODY(get_put_action__get_fail__invalid_context) 233 { 234 store::backend backend = store::backend::open_rw(fs::path("test.db")); 235 backend.database().exec("PRAGMA foreign_keys = OFF"); 236 backend.database().exec("INSERT INTO actions (action_id, context_id) " 237 "VALUES (123, 456)"); 238 239 store::transaction tx = backend.start(); 240 ATF_REQUIRE_THROW_RE(store::error, "context 456: does not exist", 241 tx.get_action(123)); 242 } 243 244 245 ATF_TEST_CASE(get_put_action__put_fail); 246 ATF_TEST_CASE_HEAD(get_put_action__put_fail) 247 { 248 logging::set_inmemory(); 249 set_md_var("require.files", store::detail::schema_file().c_str()); 250 } 251 ATF_TEST_CASE_BODY(get_put_action__put_fail) 252 { 253 store::backend backend = store::backend::open_rw(fs::path("test.db")); 254 store::transaction tx = backend.start(); 255 const engine::context context(fs::path("/foo/bar"), 256 std::map< std::string, std::string >()); 257 const int64_t context_id = tx.put_context(context); 258 const engine::action action(context); 259 backend.database().exec("DROP TABLE actions"); 260 ATF_REQUIRE_THROW(store::error, tx.put_action(action, context_id)); 261 tx.commit(); 262 } 263 264 265 ATF_TEST_CASE(get_action_results__none); 266 ATF_TEST_CASE_HEAD(get_action_results__none) 267 { 268 logging::set_inmemory(); 269 set_md_var("require.files", store::detail::schema_file().c_str()); 270 } 271 ATF_TEST_CASE_BODY(get_action_results__none) 272 { 273 store::backend backend = store::backend::open_rw(fs::path("test.db")); 274 store::transaction tx = backend.start(); 275 store::results_iterator iter = tx.get_action_results(1); 276 ATF_REQUIRE(!iter); 277 } 278 279 280 ATF_TEST_CASE(get_action_results__many); 281 ATF_TEST_CASE_HEAD(get_action_results__many) 282 { 283 logging::set_inmemory(); 284 set_md_var("require.files", store::detail::schema_file().c_str()); 285 } 286 ATF_TEST_CASE_BODY(get_action_results__many) 287 { 288 store::backend backend = store::backend::open_rw(fs::path("test.db")); 289 290 store::transaction tx = backend.start(); 291 292 const engine::context context(fs::path("/foo/bar"), 293 std::map< std::string, std::string >()); 294 const engine::action action(context); 295 const int64_t context_id = tx.put_context(context); 296 const int64_t action_id = tx.put_action(action, context_id); 297 const int64_t action2_id = tx.put_action(action, context_id); 298 299 const datetime::timestamp start_time1 = datetime::timestamp::from_values( 300 2012, 01, 30, 22, 10, 00, 0); 301 const datetime::timestamp end_time1 = datetime::timestamp::from_values( 302 2012, 01, 30, 22, 15, 30, 1234); 303 const datetime::timestamp start_time2 = datetime::timestamp::from_values( 304 2012, 01, 30, 22, 15, 40, 987); 305 const datetime::timestamp end_time2 = datetime::timestamp::from_values( 306 2012, 01, 30, 22, 16, 0, 0); 307 308 atf::utils::create_file("unused.txt", "unused file\n"); 309 310 engine::test_program test_program_1( 311 "plain", fs::path("a/prog1"), fs::path("/the/root"), "suite1", 312 engine::metadata_builder().build()); 313 engine::test_case_ptr test_case_1(new engine::test_case( 314 "plain", test_program_1, "main", engine::metadata_builder().build())); 315 engine::test_cases_vector test_cases_1; 316 test_cases_1.push_back(test_case_1); 317 test_program_1.set_test_cases(test_cases_1); 318 const engine::test_result result_1(engine::test_result::passed); 319 { 320 const int64_t tp_id = tx.put_test_program(test_program_1, action_id); 321 const int64_t tc_id = tx.put_test_case(*test_case_1, tp_id); 322 atf::utils::create_file("prog1.out", "stdout of prog1\n"); 323 tx.put_test_case_file("__STDOUT__", fs::path("prog1.out"), tc_id); 324 tx.put_test_case_file("unused.txt", fs::path("unused.txt"), tc_id); 325 tx.put_result(result_1, tc_id, start_time1, end_time1); 326 327 const int64_t tp2_id = tx.put_test_program(test_program_1, action2_id); 328 const int64_t tc2_id = tx.put_test_case(*test_case_1, tp2_id); 329 tx.put_test_case_file("__STDOUT__", fs::path("unused.txt"), tc2_id); 330 tx.put_test_case_file("__STDERR__", fs::path("unused.txt"), tc2_id); 331 tx.put_result(result_1, tc2_id, start_time1, end_time1); 332 } 333 334 engine::test_program test_program_2( 335 "plain", fs::path("b/prog2"), fs::path("/the/root"), "suite2", 336 engine::metadata_builder().build()); 337 engine::test_case_ptr test_case_2(new engine::test_case( 338 "plain", test_program_2, "main", engine::metadata_builder().build())); 339 engine::test_cases_vector test_cases_2; 340 test_cases_2.push_back(test_case_2); 341 test_program_2.set_test_cases(test_cases_2); 342 const engine::test_result result_2(engine::test_result::failed, 343 "Some text"); 344 { 345 const int64_t tp_id = tx.put_test_program(test_program_2, action_id); 346 const int64_t tc_id = tx.put_test_case(*test_case_2, tp_id); 347 atf::utils::create_file("prog2.err", "stderr of prog2\n"); 348 tx.put_test_case_file("__STDERR__", fs::path("prog2.err"), tc_id); 349 tx.put_test_case_file("unused.txt", fs::path("unused.txt"), tc_id); 350 tx.put_result(result_2, tc_id, start_time2, end_time2); 351 } 352 353 tx.commit(); 354 355 store::transaction tx2 = backend.start(); 356 store::results_iterator iter = tx2.get_action_results(action_id); 357 ATF_REQUIRE(iter); 358 ATF_REQUIRE(test_program_1 == *iter.test_program()); 359 ATF_REQUIRE_EQ("main", iter.test_case_name()); 360 ATF_REQUIRE_EQ("stdout of prog1\n", iter.stdout_contents()); 361 ATF_REQUIRE(iter.stderr_contents().empty()); 362 ATF_REQUIRE(result_1 == iter.result()); 363 ATF_REQUIRE(end_time1 - start_time1 == iter.duration()); 364 ATF_REQUIRE(++iter); 365 ATF_REQUIRE(test_program_2 == *iter.test_program()); 366 ATF_REQUIRE_EQ("main", iter.test_case_name()); 367 ATF_REQUIRE(iter.stdout_contents().empty()); 368 ATF_REQUIRE_EQ("stderr of prog2\n", iter.stderr_contents()); 369 ATF_REQUIRE(result_2 == iter.result()); 370 ATF_REQUIRE(end_time2 - start_time2 == iter.duration()); 371 ATF_REQUIRE(!++iter); 372 } 373 374 375 ATF_TEST_CASE(get_latest_action__ok); 376 ATF_TEST_CASE_HEAD(get_latest_action__ok) 377 { 378 logging::set_inmemory(); 379 set_md_var("require.files", store::detail::schema_file().c_str()); 380 } 381 ATF_TEST_CASE_BODY(get_latest_action__ok) 382 { 383 store::backend backend = store::backend::open_rw(fs::path("test.db")); 384 const engine::context context1(fs::path("/foo/bar"), 385 std::map< std::string, std::string >()); 386 const engine::context context2(fs::path("/foo/baz"), 387 std::map< std::string, std::string >()); 388 const engine::action exp_action1(context1); 389 const engine::action exp_action2(context2); 390 391 int64_t id2; 392 { 393 store::transaction tx = backend.start(); 394 const int64_t context1_id = tx.put_context(context1); 395 const int64_t context2_id = tx.put_context(context2); 396 (void)tx.put_action(exp_action1, context1_id); 397 id2 = tx.put_action(exp_action2, context2_id); 398 tx.commit(); 399 } 400 { 401 store::transaction tx = backend.start(); 402 const std::pair< int64_t, engine::action > latest_action = 403 tx.get_latest_action(); 404 tx.rollback(); 405 406 ATF_REQUIRE(id2 == latest_action.first); 407 ATF_REQUIRE(exp_action2 == latest_action.second); 408 } 409 } 410 411 412 ATF_TEST_CASE(get_latest_action__none); 413 ATF_TEST_CASE_HEAD(get_latest_action__none) 414 { 415 logging::set_inmemory(); 416 set_md_var("require.files", store::detail::schema_file().c_str()); 417 } 418 ATF_TEST_CASE_BODY(get_latest_action__none) 419 { 420 store::backend backend = store::backend::open_rw(fs::path("test.db")); 421 store::transaction tx = backend.start(); 422 ATF_REQUIRE_THROW_RE(store::error, "No actions", tx.get_latest_action()); 423 } 424 425 426 ATF_TEST_CASE(get_latest_action__invalid_context); 427 ATF_TEST_CASE_HEAD(get_latest_action__invalid_context) 428 { 429 logging::set_inmemory(); 430 set_md_var("require.files", store::detail::schema_file().c_str()); 431 } 432 ATF_TEST_CASE_BODY(get_latest_action__invalid_context) 433 { 434 store::backend backend = store::backend::open_rw(fs::path("test.db")); 435 backend.database().exec("PRAGMA foreign_keys = OFF"); 436 backend.database().exec("INSERT INTO actions (action_id, context_id) " 437 "VALUES (123, 456)"); 438 439 store::transaction tx = backend.start(); 440 ATF_REQUIRE_THROW_RE(store::error, "context 456: does not exist", 441 tx.get_latest_action()); 442 } 443 444 445 ATF_TEST_CASE(get_put_context__ok); 446 ATF_TEST_CASE_HEAD(get_put_context__ok) 447 { 448 logging::set_inmemory(); 449 set_md_var("require.files", store::detail::schema_file().c_str()); 450 } 451 ATF_TEST_CASE_BODY(get_put_context__ok) 452 { 453 store::backend backend = store::backend::open_rw(fs::path("test.db")); 454 455 std::map< std::string, std::string > env1; 456 env1["A1"] = "foo"; 457 env1["A2"] = "bar"; 458 std::map< std::string, std::string > env2; 459 const engine::context exp_context1(fs::path("/foo/bar"), env1); 460 const engine::context exp_context2(fs::path("/foo/bar"), env1); 461 const engine::context exp_context3(fs::path("/foo/baz"), env2); 462 463 int64_t id1, id2, id3; 464 { 465 store::transaction tx = backend.start(); 466 id1 = tx.put_context(exp_context1); 467 id3 = tx.put_context(exp_context3); 468 id2 = tx.put_context(exp_context2); 469 tx.commit(); 470 } 471 { 472 store::transaction tx = backend.start(); 473 const engine::context context1 = tx.get_context(id1); 474 const engine::context context2 = tx.get_context(id2); 475 const engine::context context3 = tx.get_context(id3); 476 tx.rollback(); 477 478 ATF_REQUIRE(exp_context1 == context1); 479 ATF_REQUIRE(exp_context2 == context2); 480 ATF_REQUIRE(exp_context3 == context3); 481 } 482 } 483 484 485 ATF_TEST_CASE(get_put_context__get_fail__missing); 486 ATF_TEST_CASE_HEAD(get_put_context__get_fail__missing) 487 { 488 logging::set_inmemory(); 489 set_md_var("require.files", store::detail::schema_file().c_str()); 490 } 491 ATF_TEST_CASE_BODY(get_put_context__get_fail__missing) 492 { 493 store::backend backend = store::backend::open_rw(fs::path("test.db")); 494 495 store::transaction tx = backend.start(); 496 ATF_REQUIRE_THROW_RE(store::error, "context 456: does not exist", 497 tx.get_context(456)); 498 } 499 500 501 ATF_TEST_CASE(get_put_context__get_fail__invalid_cwd); 502 ATF_TEST_CASE_HEAD(get_put_context__get_fail__invalid_cwd) 503 { 504 logging::set_inmemory(); 505 set_md_var("require.files", store::detail::schema_file().c_str()); 506 } 507 ATF_TEST_CASE_BODY(get_put_context__get_fail__invalid_cwd) 508 { 509 store::backend backend = store::backend::open_rw(fs::path("test.db")); 510 511 sqlite::statement stmt = backend.database().create_statement( 512 "INSERT INTO contexts (context_id, cwd) VALUES (78, :cwd)"); 513 const char buffer[10] = "foo bar"; 514 stmt.bind(":cwd", sqlite::blob(buffer, sizeof(buffer))); 515 stmt.step_without_results(); 516 517 store::transaction tx = backend.start(); 518 ATF_REQUIRE_THROW_RE(store::error, "context 78: .*cwd.*not a string", 519 tx.get_context(78)); 520 } 521 522 523 ATF_TEST_CASE(get_put_context__get_fail__invalid_env_vars); 524 ATF_TEST_CASE_HEAD(get_put_context__get_fail__invalid_env_vars) 525 { 526 logging::set_inmemory(); 527 set_md_var("require.files", store::detail::schema_file().c_str()); 528 } 529 ATF_TEST_CASE_BODY(get_put_context__get_fail__invalid_env_vars) 530 { 531 store::backend backend = store::backend::open_rw(fs::path("test.db")); 532 533 backend.database().exec("INSERT INTO contexts (context_id, cwd) " 534 "VALUES (10, '/foo/bar')"); 535 backend.database().exec("INSERT INTO contexts (context_id, cwd) " 536 "VALUES (20, '/foo/bar')"); 537 538 const char buffer[10] = "foo bar"; 539 540 { 541 sqlite::statement stmt = backend.database().create_statement( 542 "INSERT INTO env_vars (context_id, var_name, var_value) " 543 "VALUES (10, :var_name, 'abc')"); 544 stmt.bind(":var_name", sqlite::blob(buffer, sizeof(buffer))); 545 stmt.step_without_results(); 546 } 547 548 { 549 sqlite::statement stmt = backend.database().create_statement( 550 "INSERT INTO env_vars (context_id, var_name, var_value) " 551 "VALUES (20, 'abc', :var_value)"); 552 stmt.bind(":var_value", sqlite::blob(buffer, sizeof(buffer))); 553 stmt.step_without_results(); 554 } 555 556 store::transaction tx = backend.start(); 557 ATF_REQUIRE_THROW_RE(store::error, "context 10: .*var_name.*not a string", 558 tx.get_context(10)); 559 ATF_REQUIRE_THROW_RE(store::error, "context 20: .*var_value.*not a string", 560 tx.get_context(20)); 561 } 562 563 564 ATF_TEST_CASE(get_put_context__put_fail); 565 ATF_TEST_CASE_HEAD(get_put_context__put_fail) 566 { 567 logging::set_inmemory(); 568 set_md_var("require.files", store::detail::schema_file().c_str()); 569 } 570 ATF_TEST_CASE_BODY(get_put_context__put_fail) 571 { 572 (void)store::backend::open_rw(fs::path("test.db")); 573 store::backend backend = store::backend::open_ro(fs::path("test.db")); 574 store::transaction tx = backend.start(); 575 const engine::context context(fs::path("/foo/bar"), 576 std::map< std::string, std::string >()); 577 ATF_REQUIRE_THROW(store::error, tx.put_context(context)); 578 tx.commit(); 579 } 580 581 582 ATF_TEST_CASE(put_test_program__ok); 583 ATF_TEST_CASE_HEAD(put_test_program__ok) 584 { 585 logging::set_inmemory(); 586 set_md_var("require.files", store::detail::schema_file().c_str()); 587 } 588 ATF_TEST_CASE_BODY(put_test_program__ok) 589 { 590 const engine::metadata md = engine::metadata_builder() 591 .add_custom("var1", "value1") 592 .add_custom("var2", "value2") 593 .build(); 594 const engine::test_program test_program( 595 "mock", fs::path("the/binary"), fs::path("/some//root"), 596 "the-suite", md); 597 598 store::backend backend = store::backend::open_rw(fs::path("test.db")); 599 backend.database().exec("PRAGMA foreign_keys = OFF"); 600 store::transaction tx = backend.start(); 601 const int64_t test_program_id = tx.put_test_program(test_program, 15); 602 tx.commit(); 603 604 { 605 sqlite::statement stmt = backend.database().create_statement( 606 "SELECT * FROM test_programs"); 607 608 ATF_REQUIRE(stmt.step()); 609 ATF_REQUIRE_EQ(test_program_id, 610 stmt.safe_column_int64("test_program_id")); 611 ATF_REQUIRE_EQ(15, stmt.safe_column_int64("action_id")); 612 ATF_REQUIRE_EQ("/some/root/the/binary", 613 stmt.safe_column_text("absolute_path")); 614 ATF_REQUIRE_EQ("/some/root", stmt.safe_column_text("root")); 615 ATF_REQUIRE_EQ("the/binary", stmt.safe_column_text("relative_path")); 616 ATF_REQUIRE_EQ("the-suite", stmt.safe_column_text("test_suite_name")); 617 ATF_REQUIRE(!stmt.step()); 618 } 619 } 620 621 622 ATF_TEST_CASE(put_test_program__fail); 623 ATF_TEST_CASE_HEAD(put_test_program__fail) 624 { 625 logging::set_inmemory(); 626 set_md_var("require.files", store::detail::schema_file().c_str()); 627 } 628 ATF_TEST_CASE_BODY(put_test_program__fail) 629 { 630 const engine::test_program test_program( 631 "mock", fs::path("the/binary"), fs::path("/some/root"), "the-suite", 632 engine::metadata_builder().build()); 633 634 store::backend backend = store::backend::open_rw(fs::path("test.db")); 635 store::transaction tx = backend.start(); 636 ATF_REQUIRE_THROW(store::error, tx.put_test_program(test_program, -1)); 637 tx.commit(); 638 } 639 640 641 ATF_TEST_CASE(put_test_case__ok); 642 ATF_TEST_CASE_HEAD(put_test_case__ok) 643 { 644 logging::set_inmemory(); 645 set_md_var("require.files", store::detail::schema_file().c_str()); 646 } 647 ATF_TEST_CASE_BODY(put_test_case__ok) 648 { 649 engine::test_program test_program( 650 "atf", fs::path("the/binary"), fs::path("/some/root"), "the-suite", 651 engine::metadata_builder().build()); 652 653 const engine::test_case_ptr test_case1(new engine::test_case( 654 "atf", test_program, "tc1", engine::metadata_builder().build())); 655 656 const engine::metadata md2 = engine::metadata_builder() 657 .add_allowed_architecture("powerpc") 658 .add_allowed_architecture("x86_64") 659 .add_allowed_platform("amd64") 660 .add_allowed_platform("macppc") 661 .add_custom("X-user1", "value1") 662 .add_custom("X-user2", "value2") 663 .add_required_config("var1") 664 .add_required_config("var2") 665 .add_required_config("var3") 666 .add_required_file(fs::path("/file1/yes")) 667 .add_required_file(fs::path("/file2/foo")) 668 .add_required_program(fs::path("/bin/ls")) 669 .add_required_program(fs::path("cp")) 670 .set_description("The description") 671 .set_has_cleanup(true) 672 .set_required_memory(units::bytes::parse("1k")) 673 .set_required_user("root") 674 .set_timeout(datetime::delta(520, 0)) 675 .build(); 676 const engine::test_case_ptr test_case2(new engine::test_case( 677 "atf", test_program, "tc2", md2)); 678 679 { 680 engine::test_cases_vector test_cases; 681 test_cases.push_back(test_case1); 682 test_cases.push_back(test_case2); 683 test_program.set_test_cases(test_cases); 684 } 685 686 store::backend backend = store::backend::open_rw(fs::path("test.db")); 687 backend.database().exec("PRAGMA foreign_keys = OFF"); 688 int64_t test_program_id; 689 { 690 store::transaction tx = backend.start(); 691 test_program_id = tx.put_test_program(test_program, 15); 692 tx.put_test_case(*test_case1, test_program_id); 693 tx.put_test_case(*test_case2, test_program_id); 694 tx.commit(); 695 } 696 697 store::transaction tx = backend.start(); 698 const engine::test_program_ptr loaded_test_program = 699 store::detail::get_test_program(backend, test_program_id); 700 ATF_REQUIRE(test_program == *loaded_test_program); 701 } 702 703 704 ATF_TEST_CASE(put_test_case__fail); 705 ATF_TEST_CASE_HEAD(put_test_case__fail) 706 { 707 logging::set_inmemory(); 708 set_md_var("require.files", store::detail::schema_file().c_str()); 709 } 710 ATF_TEST_CASE_BODY(put_test_case__fail) 711 { 712 // TODO(jmmv): Use a mock test program and test case. 713 const engine::test_program test_program( 714 "plain", fs::path("the/binary"), fs::path("/some/root"), "the-suite", 715 engine::metadata_builder().build()); 716 const engine::test_case test_case("plain", test_program, "main", 717 engine::metadata_builder().build()); 718 719 store::backend backend = store::backend::open_rw(fs::path("test.db")); 720 store::transaction tx = backend.start(); 721 ATF_REQUIRE_THROW(store::error, tx.put_test_case(test_case, -1)); 722 tx.commit(); 723 } 724 725 726 ATF_TEST_CASE(put_test_case_file__empty); 727 ATF_TEST_CASE_HEAD(put_test_case_file__empty) 728 { 729 logging::set_inmemory(); 730 set_md_var("require.files", store::detail::schema_file().c_str()); 731 } 732 ATF_TEST_CASE_BODY(put_test_case_file__empty) 733 { 734 atf::utils::create_file("input.txt", ""); 735 736 store::backend backend = store::backend::open_rw(fs::path("test.db")); 737 backend.database().exec("PRAGMA foreign_keys = OFF"); 738 store::transaction tx = backend.start(); 739 const optional< int64_t > file_id = tx.put_test_case_file( 740 "my-file", fs::path("input.txt"), 123L); 741 tx.commit(); 742 ATF_REQUIRE(!file_id); 743 744 sqlite::statement stmt = backend.database().create_statement( 745 "SELECT * FROM test_case_files NATURAL JOIN files"); 746 ATF_REQUIRE(!stmt.step()); 747 } 748 749 750 ATF_TEST_CASE(put_test_case_file__some); 751 ATF_TEST_CASE_HEAD(put_test_case_file__some) 752 { 753 logging::set_inmemory(); 754 set_md_var("require.files", store::detail::schema_file().c_str()); 755 } 756 ATF_TEST_CASE_BODY(put_test_case_file__some) 757 { 758 const char contents[] = "This is a test!"; 759 760 atf::utils::create_file("input.txt", contents); 761 762 store::backend backend = store::backend::open_rw(fs::path("test.db")); 763 backend.database().exec("PRAGMA foreign_keys = OFF"); 764 store::transaction tx = backend.start(); 765 const optional< int64_t > file_id = tx.put_test_case_file( 766 "my-file", fs::path("input.txt"), 123L); 767 tx.commit(); 768 ATF_REQUIRE(file_id); 769 770 sqlite::statement stmt = backend.database().create_statement( 771 "SELECT * FROM test_case_files NATURAL JOIN files"); 772 773 ATF_REQUIRE(stmt.step()); 774 ATF_REQUIRE_EQ(123L, stmt.safe_column_int64("test_case_id")); 775 ATF_REQUIRE_EQ("my-file", stmt.safe_column_text("file_name")); 776 const sqlite::blob blob = stmt.safe_column_blob("contents"); 777 ATF_REQUIRE(std::strlen(contents) == static_cast< std::size_t >(blob.size)); 778 ATF_REQUIRE(std::memcmp(contents, blob.memory, blob.size) == 0); 779 ATF_REQUIRE(!stmt.step()); 780 } 781 782 783 ATF_TEST_CASE(put_test_case_file__fail); 784 ATF_TEST_CASE_HEAD(put_test_case_file__fail) 785 { 786 logging::set_inmemory(); 787 set_md_var("require.files", store::detail::schema_file().c_str()); 788 } 789 ATF_TEST_CASE_BODY(put_test_case_file__fail) 790 { 791 store::backend backend = store::backend::open_rw(fs::path("test.db")); 792 backend.database().exec("PRAGMA foreign_keys = OFF"); 793 store::transaction tx = backend.start(); 794 ATF_REQUIRE_THROW(store::error, 795 tx.put_test_case_file("foo", fs::path("missing"), 1L)); 796 tx.commit(); 797 798 sqlite::statement stmt = backend.database().create_statement( 799 "SELECT * FROM test_case_files NATURAL JOIN files"); 800 ATF_REQUIRE(!stmt.step()); 801 } 802 803 804 ATF_TEST_CASE(put_result__ok__broken); 805 ATF_TEST_CASE_HEAD(put_result__ok__broken) 806 { 807 logging::set_inmemory(); 808 set_md_var("require.files", store::detail::schema_file().c_str()); 809 } 810 ATF_TEST_CASE_BODY(put_result__ok__broken) 811 { 812 const engine::test_result result(engine::test_result::broken, "a b cd"); 813 do_put_result_ok_test(result, "broken", "a b cd"); 814 } 815 816 817 ATF_TEST_CASE(put_result__ok__expected_failure); 818 ATF_TEST_CASE_HEAD(put_result__ok__expected_failure) 819 { 820 logging::set_inmemory(); 821 set_md_var("require.files", store::detail::schema_file().c_str()); 822 } 823 ATF_TEST_CASE_BODY(put_result__ok__expected_failure) 824 { 825 const engine::test_result result(engine::test_result::expected_failure, 826 "a b cd"); 827 do_put_result_ok_test(result, "expected_failure", "a b cd"); 828 } 829 830 831 ATF_TEST_CASE(put_result__ok__failed); 832 ATF_TEST_CASE_HEAD(put_result__ok__failed) 833 { 834 logging::set_inmemory(); 835 set_md_var("require.files", store::detail::schema_file().c_str()); 836 } 837 ATF_TEST_CASE_BODY(put_result__ok__failed) 838 { 839 const engine::test_result result(engine::test_result::failed, "a b cd"); 840 do_put_result_ok_test(result, "failed", "a b cd"); 841 } 842 843 844 ATF_TEST_CASE(put_result__ok__passed); 845 ATF_TEST_CASE_HEAD(put_result__ok__passed) 846 { 847 logging::set_inmemory(); 848 set_md_var("require.files", store::detail::schema_file().c_str()); 849 } 850 ATF_TEST_CASE_BODY(put_result__ok__passed) 851 { 852 const engine::test_result result(engine::test_result::passed); 853 do_put_result_ok_test(result, "passed", NULL); 854 } 855 856 857 ATF_TEST_CASE(put_result__ok__skipped); 858 ATF_TEST_CASE_HEAD(put_result__ok__skipped) 859 { 860 logging::set_inmemory(); 861 set_md_var("require.files", store::detail::schema_file().c_str()); 862 } 863 ATF_TEST_CASE_BODY(put_result__ok__skipped) 864 { 865 const engine::test_result result(engine::test_result::skipped, "a b cd"); 866 do_put_result_ok_test(result, "skipped", "a b cd"); 867 } 868 869 870 ATF_TEST_CASE(put_result__fail); 871 ATF_TEST_CASE_HEAD(put_result__fail) 872 { 873 logging::set_inmemory(); 874 set_md_var("require.files", store::detail::schema_file().c_str()); 875 } 876 ATF_TEST_CASE_BODY(put_result__fail) 877 { 878 const engine::test_result result(engine::test_result::broken, "foo"); 879 880 store::backend backend = store::backend::open_rw(fs::path("test.db")); 881 store::transaction tx = backend.start(); 882 const datetime::timestamp zero = datetime::timestamp::from_microseconds(0); 883 ATF_REQUIRE_THROW(store::error, tx.put_result(result, -1, zero, zero)); 884 tx.commit(); 885 } 886 887 888 ATF_INIT_TEST_CASES(tcs) 889 { 890 ATF_ADD_TEST_CASE(tcs, commit__ok); 891 ATF_ADD_TEST_CASE(tcs, commit__fail); 892 ATF_ADD_TEST_CASE(tcs, rollback__ok); 893 894 ATF_ADD_TEST_CASE(tcs, get_put_action__ok); 895 ATF_ADD_TEST_CASE(tcs, get_put_action__get_fail__missing); 896 ATF_ADD_TEST_CASE(tcs, get_put_action__get_fail__invalid_context); 897 ATF_ADD_TEST_CASE(tcs, get_put_action__put_fail); 898 899 ATF_ADD_TEST_CASE(tcs, get_action_results__none); 900 ATF_ADD_TEST_CASE(tcs, get_action_results__many); 901 902 ATF_ADD_TEST_CASE(tcs, get_latest_action__ok); 903 ATF_ADD_TEST_CASE(tcs, get_latest_action__none); 904 ATF_ADD_TEST_CASE(tcs, get_latest_action__invalid_context); 905 906 ATF_ADD_TEST_CASE(tcs, get_put_context__ok); 907 ATF_ADD_TEST_CASE(tcs, get_put_context__get_fail__missing); 908 ATF_ADD_TEST_CASE(tcs, get_put_context__get_fail__invalid_cwd); 909 ATF_ADD_TEST_CASE(tcs, get_put_context__get_fail__invalid_env_vars); 910 ATF_ADD_TEST_CASE(tcs, get_put_context__put_fail); 911 912 ATF_ADD_TEST_CASE(tcs, put_test_program__ok); 913 ATF_ADD_TEST_CASE(tcs, put_test_program__fail); 914 ATF_ADD_TEST_CASE(tcs, put_test_case__ok); 915 ATF_ADD_TEST_CASE(tcs, put_test_case__fail); 916 ATF_ADD_TEST_CASE(tcs, put_test_case_file__empty); 917 ATF_ADD_TEST_CASE(tcs, put_test_case_file__some); 918 ATF_ADD_TEST_CASE(tcs, put_test_case_file__fail); 919 920 ATF_ADD_TEST_CASE(tcs, put_result__ok__broken); 921 ATF_ADD_TEST_CASE(tcs, put_result__ok__expected_failure); 922 ATF_ADD_TEST_CASE(tcs, put_result__ok__failed); 923 ATF_ADD_TEST_CASE(tcs, put_result__ok__passed); 924 ATF_ADD_TEST_CASE(tcs, put_result__ok__skipped); 925 ATF_ADD_TEST_CASE(tcs, put_result__fail); 926 } 927