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 extern "C" { 32 #include <stdint.h> 33 } 34 35 #include <fstream> 36 #include <map> 37 #include <utility> 38 39 #include "engine/action.hpp" 40 #include "engine/context.hpp" 41 #include "engine/test_result.hpp" 42 #include "store/backend.hpp" 43 #include "store/dbtypes.hpp" 44 #include "store/exceptions.hpp" 45 #include "utils/datetime.hpp" 46 #include "utils/defs.hpp" 47 #include "utils/format/macros.hpp" 48 #include "utils/logging/macros.hpp" 49 #include "utils/optional.ipp" 50 #include "utils/sanity.hpp" 51 #include "utils/stream.hpp" 52 #include "utils/sqlite/database.hpp" 53 #include "utils/sqlite/exceptions.hpp" 54 #include "utils/sqlite/statement.ipp" 55 #include "utils/sqlite/transaction.hpp" 56 #include "utils/units.hpp" 57 58 namespace datetime = utils::datetime; 59 namespace fs = utils::fs; 60 namespace sqlite = utils::sqlite; 61 namespace units = utils::units; 62 63 using utils::none; 64 using utils::optional; 65 66 67 namespace { 68 69 70 /// Retrieves the environment variables of a context. 71 /// 72 /// \param db The SQLite database. 73 /// \param context_id The identifier of the context. 74 /// 75 /// \return The environment variables of the specified context. 76 /// 77 /// \throw sqlite::error If there is a problem storing the variables. 78 static std::map< std::string, std::string > 79 get_env_vars(sqlite::database& db, const int64_t context_id) 80 { 81 std::map< std::string, std::string > env; 82 83 sqlite::statement stmt = db.create_statement( 84 "SELECT var_name, var_value FROM env_vars " 85 "WHERE context_id == :context_id"); 86 stmt.bind(":context_id", context_id); 87 88 while (stmt.step()) { 89 const std::string name = stmt.safe_column_text("var_name"); 90 const std::string value = stmt.safe_column_text("var_value"); 91 env[name] = value; 92 } 93 94 return env; 95 } 96 97 98 /// Retrieves a metadata object. 99 /// 100 /// \param db The SQLite database. 101 /// \param metadata_id The identifier of the metadata. 102 /// 103 /// \return A new metadata object. 104 static engine::metadata 105 get_metadata(sqlite::database& db, const int64_t metadata_id) 106 { 107 engine::metadata_builder builder; 108 109 sqlite::statement stmt = db.create_statement( 110 "SELECT * FROM metadatas WHERE metadata_id == :metadata_id"); 111 stmt.bind(":metadata_id", metadata_id); 112 while (stmt.step()) { 113 const std::string name = stmt.safe_column_text("property_name"); 114 const std::string value = stmt.safe_column_text("property_value"); 115 builder.set_string(name, value); 116 } 117 118 return builder.build(); 119 } 120 121 122 /// Gets a file from the database. 123 /// 124 /// \param db The database to query the file from. 125 /// \param file_id The identifier of the file to be queried. 126 /// 127 /// \return A textual representation of the file contents. 128 /// 129 /// \throw integrity_error If there is any problem in the loaded data or if the 130 /// file cannot be found. 131 static std::string 132 get_file(sqlite::database& db, const int64_t file_id) 133 { 134 sqlite::statement stmt = db.create_statement( 135 "SELECT contents FROM files WHERE file_id == :file_id"); 136 stmt.bind(":file_id", file_id); 137 if (!stmt.step()) 138 throw store::integrity_error(F("Cannot find referenced file %s") % 139 file_id); 140 141 try { 142 const sqlite::blob raw_contents = stmt.safe_column_blob("contents"); 143 const std::string contents( 144 static_cast< const char *>(raw_contents.memory), raw_contents.size); 145 146 #if defined(__minix) && !defined(NDEBUG) 147 const bool more = 148 #endif /* defined(__minix) && !defined(NDEBUG) */ 149 stmt.step(); 150 INV(!more); 151 152 return contents; 153 } catch (const sqlite::error& e) { 154 throw store::integrity_error(e.what()); 155 } 156 } 157 158 159 /// Gets all the test cases within a particular test program. 160 /// 161 /// \param db The database to query the information from. 162 /// \param test_program_id The identifier of the test program whose test cases 163 /// to query. 164 /// \param test_program The test program itself, needed to establish a binding 165 /// between the loaded test cases and the test program. 166 /// \param interface The interface type of the test cases to be loaded. This 167 /// assumes that all test cases within a test program share the same 168 /// interface, which is a pretty reasonable assumption. 169 /// 170 /// \return The collection of loaded test cases. 171 /// 172 /// \throw integrity_error If there is any problem in the loaded data. 173 static engine::test_cases_vector 174 get_test_cases(sqlite::database& db, const int64_t test_program_id, 175 const engine::test_program& test_program, 176 const std::string& interface) 177 { 178 engine::test_cases_vector test_cases; 179 180 sqlite::statement stmt = db.create_statement( 181 "SELECT name, metadata_id " 182 "FROM test_cases WHERE test_program_id == :test_program_id"); 183 stmt.bind(":test_program_id", test_program_id); 184 while (stmt.step()) { 185 const std::string name = stmt.safe_column_text("name"); 186 const int64_t metadata_id = stmt.safe_column_int64("metadata_id"); 187 188 const engine::metadata metadata = get_metadata(db, metadata_id); 189 engine::test_case_ptr test_case( 190 new engine::test_case(interface, test_program, name, metadata)); 191 LD(F("Loaded test case '%s'") % test_case->name()); 192 test_cases.push_back(test_case); 193 } 194 195 return test_cases; 196 } 197 198 199 /// Retrieves a result from the database. 200 /// 201 /// \param stmt The statement with the data for the result to load. 202 /// \param type_column The name of the column containing the type of the result. 203 /// \param reason_column The name of the column containing the reason for the 204 /// result, if any. 205 /// 206 /// \return The loaded result. 207 /// 208 /// \throw integrity_error If the data in the database is invalid. 209 static engine::test_result 210 parse_result(sqlite::statement& stmt, const char* type_column, 211 const char* reason_column) 212 { 213 using engine::test_result; 214 215 try { 216 const std::string type = stmt.safe_column_text(type_column); 217 if (type == "passed") { 218 if (stmt.column_type(stmt.column_id(reason_column)) != 219 sqlite::type_null) 220 throw store::integrity_error("Result of type 'passed' has a " 221 "non-NULL reason"); 222 return test_result(test_result::passed); 223 } else if (type == "broken") { 224 return test_result(test_result::broken, 225 stmt.safe_column_text(reason_column)); 226 } else if (type == "expected_failure") { 227 return test_result(test_result::expected_failure, 228 stmt.safe_column_text(reason_column)); 229 } else if (type == "failed") { 230 return test_result(test_result::failed, 231 stmt.safe_column_text(reason_column)); 232 } else if (type == "skipped") { 233 return test_result(test_result::skipped, 234 stmt.safe_column_text(reason_column)); 235 } else { 236 throw store::integrity_error(F("Unknown test result type %s") % 237 type); 238 } 239 } catch (const sqlite::error& e) { 240 throw store::integrity_error(e.what()); 241 } 242 } 243 244 245 /// Stores the environment variables of a context. 246 /// 247 /// \param db The SQLite database. 248 /// \param context_id The identifier of the context. 249 /// \param env The environment variables to store. 250 /// 251 /// \throw sqlite::error If there is a problem storing the variables. 252 static void 253 put_env_vars(sqlite::database& db, const int64_t context_id, 254 const std::map< std::string, std::string >& env) 255 { 256 sqlite::statement stmt = db.create_statement( 257 "INSERT INTO env_vars (context_id, var_name, var_value) " 258 "VALUES (:context_id, :var_name, :var_value)"); 259 stmt.bind(":context_id", context_id); 260 for (std::map< std::string, std::string >::const_iterator iter = 261 env.begin(); iter != env.end(); iter++) { 262 stmt.bind(":var_name", (*iter).first); 263 stmt.bind(":var_value", (*iter).second); 264 stmt.step_without_results(); 265 stmt.reset(); 266 } 267 } 268 269 270 /// Calculates the last rowid of a table. 271 /// 272 /// \param db The SQLite database. 273 /// \param table Name of the table. 274 /// 275 /// \return The last rowid; 0 if the table is empty. 276 static int64_t 277 last_rowid(sqlite::database& db, const std::string& table) 278 { 279 sqlite::statement stmt = db.create_statement( 280 F("SELECT MAX(ROWID) AS max_rowid FROM %s") % table); 281 stmt.step(); 282 if (stmt.column_type(0) == sqlite::type_null) { 283 return 0; 284 } else { 285 INV(stmt.column_type(0) == sqlite::type_integer); 286 return stmt.column_int64(0); 287 } 288 } 289 290 291 /// Stores a metadata object. 292 /// 293 /// \param db The database into which to store the information. 294 /// \param md The metadata to store. 295 /// 296 /// \return The identifier of the new metadata object. 297 static int64_t 298 put_metadata(sqlite::database& db, const engine::metadata& md) 299 { 300 const engine::properties_map props = md.to_properties(); 301 302 const int64_t metadata_id = last_rowid(db, "metadatas"); 303 304 sqlite::statement stmt = db.create_statement( 305 "INSERT INTO metadatas (metadata_id, property_name, property_value) " 306 "VALUES (:metadata_id, :property_name, :property_value)"); 307 stmt.bind(":metadata_id", metadata_id); 308 309 for (engine::properties_map::const_iterator iter = props.begin(); 310 iter != props.end(); ++iter) { 311 stmt.bind(":property_name", (*iter).first); 312 stmt.bind(":property_value", (*iter).second); 313 stmt.step_without_results(); 314 stmt.reset(); 315 } 316 317 return metadata_id; 318 } 319 320 321 /// Stores an arbitrary file into the database as a BLOB. 322 /// 323 /// \param db The database into which to store the file. 324 /// \param path Path to the file to be stored. 325 /// 326 /// \return The identifier of the stored file, or none if the file was empty. 327 /// 328 /// \throw sqlite::error If there are problems writing to the database. 329 static optional< int64_t > 330 put_file(sqlite::database& db, const fs::path& path) 331 { 332 std::ifstream input(path.c_str()); 333 if (!input) 334 throw store::error(F("Cannot open file %s") % path); 335 336 try { 337 if (utils::stream_length(input) == 0) 338 return none; 339 } catch (const std::runtime_error& e) { 340 // Skipping empty files is an optimization. If we fail to calculate the 341 // size of the file, just ignore the problem. If there are real issues 342 // with the file, the read below will fail anyway. 343 LD(F("Cannot determine if file is empty: %s") % e.what()); 344 } 345 346 // TODO(jmmv): This will probably cause an unreasonable amount of memory 347 // consumption if we decide to store arbitrary files in the database (other 348 // than stdout or stderr). Should this happen, we need to investigate a 349 // better way to feel blobs into SQLite. 350 const std::string contents = utils::read_stream(input); 351 352 sqlite::statement stmt = db.create_statement( 353 "INSERT INTO files (contents) VALUES (:contents)"); 354 stmt.bind(":contents", sqlite::blob(contents.c_str(), contents.length())); 355 stmt.step_without_results(); 356 357 return optional< int64_t >(db.last_insert_rowid()); 358 } 359 360 361 } // anonymous namespace 362 363 364 /// Loads a specific test program from the database. 365 /// 366 /// \param backend_ The store backend we are dealing with. 367 /// \param id The identifier of the test program to load. 368 /// 369 /// \return The instantiated test program. 370 /// 371 /// \throw integrity_error If the data read from the database cannot be properly 372 /// interpreted. 373 engine::test_program_ptr 374 store::detail::get_test_program(backend& backend_, const int64_t id) 375 { 376 sqlite::database& db = backend_.database(); 377 378 engine::test_program_ptr test_program; 379 sqlite::statement stmt = db.create_statement( 380 "SELECT * FROM test_programs WHERE test_program_id == :id"); 381 stmt.bind(":id", id); 382 stmt.step(); 383 const std::string interface = stmt.safe_column_text("interface"); 384 test_program.reset(new engine::test_program( 385 interface, 386 fs::path(stmt.safe_column_text("relative_path")), 387 fs::path(stmt.safe_column_text("root")), 388 stmt.safe_column_text("test_suite_name"), 389 get_metadata(db, stmt.safe_column_int64("metadata_id")))); 390 #if defined(__minix) && !defined(NDEBUG) 391 const bool more = 392 #endif /* defined(__minix) && !defined(NDEBUG) */ 393 stmt.step(); 394 INV(!more); 395 396 LD(F("Loaded test program '%s'; getting test cases") % 397 test_program->relative_path()); 398 test_program->set_test_cases(get_test_cases(db, id, *test_program, 399 interface)); 400 return test_program; 401 } 402 403 404 /// Internal implementation for a results iterator. 405 struct store::results_iterator::impl { 406 /// The store backend we are dealing with. 407 store::backend _backend; 408 409 /// The statement to iterate on. 410 sqlite::statement _stmt; 411 412 /// A cache for the last loaded test program. 413 optional< std::pair< int64_t, engine::test_program_ptr > > 414 _last_test_program; 415 416 /// Whether the iterator is still valid or not. 417 bool _valid; 418 419 /// Constructor. 420 impl(store::backend& backend_, const int64_t action_id_) : 421 _backend(backend_), 422 _stmt(backend_.database().create_statement( 423 "SELECT test_programs.test_program_id, " 424 " test_programs.interface, " 425 " test_cases.test_case_id, test_cases.name, " 426 " test_results.result_type, test_results.result_reason, " 427 " test_results.start_time, test_results.end_time " 428 "FROM test_programs " 429 " JOIN test_cases " 430 " ON test_programs.test_program_id = test_cases.test_program_id " 431 " JOIN test_results " 432 " ON test_cases.test_case_id = test_results.test_case_id " 433 "WHERE test_programs.action_id == :action_id " 434 "ORDER BY test_programs.absolute_path, test_cases.name")) 435 { 436 _stmt.bind(":action_id", action_id_); 437 _valid = _stmt.step(); 438 } 439 }; 440 441 442 /// Constructor. 443 /// 444 /// \param pimpl_ The internal implementation details of the iterator. 445 store::results_iterator::results_iterator( 446 std::shared_ptr< impl > pimpl_) : 447 _pimpl(pimpl_) 448 { 449 } 450 451 452 /// Destructor. 453 store::results_iterator::~results_iterator(void) 454 { 455 } 456 457 458 /// Moves the iterator forward by one result. 459 /// 460 /// \return The iterator itself. 461 store::results_iterator& 462 store::results_iterator::operator++(void) 463 { 464 _pimpl->_valid = _pimpl->_stmt.step(); 465 return *this; 466 } 467 468 469 /// Checks whether the iterator is still valid. 470 /// 471 /// \return True if there is more elements to iterate on, false otherwise. 472 store::results_iterator::operator bool(void) const 473 { 474 return _pimpl->_valid; 475 } 476 477 478 /// Gets the test program this result belongs to. 479 /// 480 /// \return The representation of a test program. 481 const engine::test_program_ptr 482 store::results_iterator::test_program(void) const 483 { 484 const int64_t id = _pimpl->_stmt.safe_column_int64("test_program_id"); 485 if (!_pimpl->_last_test_program || 486 _pimpl->_last_test_program.get().first != id) 487 { 488 const engine::test_program_ptr tp = detail::get_test_program( 489 _pimpl->_backend, id); 490 _pimpl->_last_test_program = std::make_pair(id, tp); 491 } 492 return _pimpl->_last_test_program.get().second; 493 } 494 495 496 /// Gets the name of the test case pointed by the iterator. 497 /// 498 /// The caller can look up the test case data by using the find() method on the 499 /// test program returned by test_program(). 500 /// 501 /// \return A test case name, unique within the test program. 502 std::string 503 store::results_iterator::test_case_name(void) const 504 { 505 return _pimpl->_stmt.safe_column_text("name"); 506 } 507 508 509 /// Gets the result of the test case pointed by the iterator. 510 /// 511 /// \return A test case result. 512 engine::test_result 513 store::results_iterator::result(void) const 514 { 515 return parse_result(_pimpl->_stmt, "result_type", "result_reason"); 516 } 517 518 519 /// Gets the duration of the test case execution. 520 /// 521 /// \return A time delta representing the run time of the test case. 522 datetime::delta 523 store::results_iterator::duration(void) const 524 { 525 const datetime::timestamp start_time = column_timestamp( 526 _pimpl->_stmt, "start_time"); 527 const datetime::timestamp end_time = column_timestamp( 528 _pimpl->_stmt, "end_time"); 529 return end_time - start_time; 530 } 531 532 533 /// Gets a file from a test case. 534 /// 535 /// \param db The database to query the file from. 536 /// \param test_case_id The identifier of the test case. 537 /// \param filename The name of the file to be retrieved. 538 /// 539 /// \return A textual representation of the file contents. 540 /// 541 /// \throw integrity_error If there is any problem in the loaded data or if the 542 /// file cannot be found. 543 static std::string 544 get_test_case_file(sqlite::database& db, const int64_t test_case_id, 545 const char* filename) 546 { 547 sqlite::statement stmt = db.create_statement( 548 "SELECT file_id FROM test_case_files " 549 "WHERE test_case_id == :test_case_id AND file_name == :file_name"); 550 stmt.bind(":test_case_id", test_case_id); 551 stmt.bind(":file_name", filename); 552 if (stmt.step()) 553 return get_file(db, stmt.safe_column_int64("file_id")); 554 else 555 return ""; 556 } 557 558 559 /// Gets the contents of stdout of a test case. 560 /// 561 /// \return A textual representation of the stdout contents of the test case. 562 /// This may of course be empty if the test case didn't print anything. 563 std::string 564 store::results_iterator::stdout_contents(void) const 565 { 566 return get_test_case_file(_pimpl->_backend.database(), 567 _pimpl->_stmt.safe_column_int64("test_case_id"), 568 "__STDOUT__"); 569 } 570 571 572 /// Gets the contents of stderr of a test case. 573 /// 574 /// \return A textual representation of the stderr contents of the test case. 575 /// This may of course be empty if the test case didn't print anything. 576 std::string 577 store::results_iterator::stderr_contents(void) const 578 { 579 return get_test_case_file(_pimpl->_backend.database(), 580 _pimpl->_stmt.safe_column_int64("test_case_id"), 581 "__STDERR__"); 582 } 583 584 585 /// Internal implementation for a store transaction. 586 struct store::transaction::impl { 587 /// The backend instance. 588 store::backend& _backend; 589 590 591 /// The SQLite database this transaction deals with. 592 sqlite::database _db; 593 594 /// The backing SQLite transaction. 595 sqlite::transaction _tx; 596 597 /// Opens a transaction. 598 /// 599 /// \param backend_ The backend this transaction is connected to. 600 impl(backend& backend_) : 601 _backend(backend_), 602 _db(backend_.database()), 603 _tx(backend_.database().begin_transaction()) 604 { 605 } 606 }; 607 608 609 /// Creates a new transaction. 610 /// 611 /// \param backend_ The backend this transaction belongs to. 612 store::transaction::transaction(backend& backend_) : 613 _pimpl(new impl(backend_)) 614 { 615 } 616 617 618 /// Destructor. 619 store::transaction::~transaction(void) 620 { 621 } 622 623 624 /// Commits the transaction. 625 /// 626 /// \throw error If there is any problem when talking to the database. 627 void 628 store::transaction::commit(void) 629 { 630 try { 631 _pimpl->_tx.commit(); 632 } catch (const sqlite::error& e) { 633 throw error(e.what()); 634 } 635 } 636 637 638 /// Rolls the transaction back. 639 /// 640 /// \throw error If there is any problem when talking to the database. 641 void 642 store::transaction::rollback(void) 643 { 644 try { 645 _pimpl->_tx.rollback(); 646 } catch (const sqlite::error& e) { 647 throw error(e.what()); 648 } 649 } 650 651 652 /// Retrieves an action from the database. 653 /// 654 /// \param action_id The identifier of the action to retrieve. 655 /// 656 /// \return The retrieved action. 657 /// 658 /// \throw error If there is a problem loading the action. 659 engine::action 660 store::transaction::get_action(const int64_t action_id) 661 { 662 try { 663 sqlite::statement stmt = _pimpl->_db.create_statement( 664 "SELECT context_id FROM actions WHERE action_id == :action_id"); 665 stmt.bind(":action_id", action_id); 666 if (!stmt.step()) 667 throw error(F("Error loading action %s: does not exist") % 668 action_id); 669 670 return engine::action( 671 get_context(stmt.safe_column_int64("context_id"))); 672 } catch (const sqlite::error& e) { 673 throw error(F("Error loading action %s: %s") % action_id % e.what()); 674 } 675 } 676 677 678 /// Creates a new iterator to scan the test results of an action. 679 /// 680 /// \param action_id The identifier of the action for which to get the results. 681 /// 682 /// \return The constructed iterator. 683 /// 684 /// \throw error If there is any problem constructing the iterator. 685 store::results_iterator 686 store::transaction::get_action_results(const int64_t action_id) 687 { 688 try { 689 return results_iterator(std::shared_ptr< results_iterator::impl >( 690 new results_iterator::impl(_pimpl->_backend, action_id))); 691 } catch (const sqlite::error& e) { 692 throw error(e.what()); 693 } 694 } 695 696 697 /// Retrieves the latest action from the database. 698 /// 699 /// \return The retrieved action. 700 /// 701 /// \throw error If there is a problem loading the action. 702 std::pair< int64_t, engine::action > 703 store::transaction::get_latest_action(void) 704 { 705 try { 706 sqlite::statement stmt = _pimpl->_db.create_statement( 707 "SELECT action_id, context_id FROM actions WHERE " 708 "action_id == (SELECT max(action_id) FROM actions)"); 709 if (!stmt.step()) 710 throw error("No actions in the database"); 711 712 const int64_t action_id = stmt.safe_column_int64("action_id"); 713 const engine::context context = get_context( 714 stmt.safe_column_int64("context_id")); 715 716 return std::pair< int64_t, engine::action >( 717 action_id, engine::action(context)); 718 } catch (const sqlite::error& e) { 719 throw error(F("Error loading latest action: %s") % e.what()); 720 } 721 } 722 723 724 /// Retrieves an context from the database. 725 /// 726 /// \param context_id The identifier of the context to retrieve. 727 /// 728 /// \return The retrieved context. 729 /// 730 /// \throw error If there is a problem loading the context. 731 engine::context 732 store::transaction::get_context(const int64_t context_id) 733 { 734 try { 735 sqlite::statement stmt = _pimpl->_db.create_statement( 736 "SELECT cwd FROM contexts WHERE context_id == :context_id"); 737 stmt.bind(":context_id", context_id); 738 if (!stmt.step()) 739 throw error(F("Error loading context %s: does not exist") % 740 context_id); 741 742 return engine::context(fs::path(stmt.safe_column_text("cwd")), 743 get_env_vars(_pimpl->_db, context_id)); 744 } catch (const sqlite::error& e) { 745 throw error(F("Error loading context %s: %s") % context_id % e.what()); 746 } 747 } 748 749 750 /// Puts an action into the database. 751 /// 752 /// \pre The action has not been put yet. 753 /// \pre The dependent objects have already been put. 754 /// \post The action is stored into the database with a new identifier. 755 /// 756 /// \param unused_action The action to put. 757 /// \param context_id The identifier for the action's context. 758 /// 759 /// \return The identifier of the inserted action. 760 /// 761 /// \throw error If there is any problem when talking to the database. 762 int64_t 763 store::transaction::put_action(const engine::action& UTILS_UNUSED_PARAM(action), 764 const int64_t context_id) 765 { 766 try { 767 sqlite::statement stmt = _pimpl->_db.create_statement( 768 "INSERT INTO actions (context_id) VALUES (:context_id)"); 769 stmt.bind(":context_id", context_id); 770 stmt.step_without_results(); 771 const int64_t action_id = _pimpl->_db.last_insert_rowid(); 772 773 return action_id; 774 } catch (const sqlite::error& e) { 775 throw error(e.what()); 776 } 777 } 778 779 780 /// Puts a context into the database. 781 /// 782 /// \pre The context has not been put yet. 783 /// \post The context is stored into the database with a new identifier. 784 /// 785 /// \param context The context to put. 786 /// 787 /// \return The identifier of the inserted context. 788 /// 789 /// \throw error If there is any problem when talking to the database. 790 int64_t 791 store::transaction::put_context(const engine::context& context) 792 { 793 try { 794 sqlite::statement stmt = _pimpl->_db.create_statement( 795 "INSERT INTO contexts (cwd) VALUES (:cwd)"); 796 stmt.bind(":cwd", context.cwd().str()); 797 stmt.step_without_results(); 798 const int64_t context_id = _pimpl->_db.last_insert_rowid(); 799 800 put_env_vars(_pimpl->_db, context_id, context.env()); 801 802 return context_id; 803 } catch (const sqlite::error& e) { 804 throw error(e.what()); 805 } 806 } 807 808 809 /// Puts a test program into the database. 810 /// 811 /// \pre The test program has not been put yet. 812 /// \post The test program is stored into the database with a new identifier. 813 /// 814 /// \param test_program The test program to put. 815 /// \param action_id The action this test program belongs to. 816 /// 817 /// \return The identifier of the inserted test program. 818 /// 819 /// \throw error If there is any problem when talking to the database. 820 int64_t 821 store::transaction::put_test_program(const engine::test_program& test_program, 822 const int64_t action_id) 823 { 824 try { 825 const int64_t metadata_id = put_metadata( 826 _pimpl->_db, test_program.get_metadata()); 827 828 sqlite::statement stmt = _pimpl->_db.create_statement( 829 "INSERT INTO test_programs (action_id, absolute_path, " 830 " root, relative_path, test_suite_name, " 831 " metadata_id, interface) " 832 "VALUES (:action_id, :absolute_path, :root, :relative_path, " 833 " :test_suite_name, :metadata_id, :interface)"); 834 stmt.bind(":action_id", action_id); 835 stmt.bind(":absolute_path", test_program.absolute_path().str()); 836 // TODO(jmmv): The root is not necessarily absolute. We need to ensure 837 // that we can recover the absolute path of the test program. Maybe we 838 // need to change the test_program to always ensure root is absolute? 839 stmt.bind(":root", test_program.root().str()); 840 stmt.bind(":relative_path", test_program.relative_path().str()); 841 stmt.bind(":test_suite_name", test_program.test_suite_name()); 842 stmt.bind(":metadata_id", metadata_id); 843 stmt.bind(":interface", test_program.interface_name()); 844 stmt.step_without_results(); 845 return _pimpl->_db.last_insert_rowid(); 846 } catch (const sqlite::error& e) { 847 throw error(e.what()); 848 } 849 } 850 851 852 /// Puts a test case into the database. 853 /// 854 /// \pre The test case has not been put yet. 855 /// \post The test case is stored into the database with a new identifier. 856 /// 857 /// \param test_case The test case to put. 858 /// \param test_program_id The test program this test case belongs to. 859 /// 860 /// \return The identifier of the inserted test case. 861 /// 862 /// \throw error If there is any problem when talking to the database. 863 int64_t 864 store::transaction::put_test_case(const engine::test_case& test_case, 865 const int64_t test_program_id) 866 { 867 try { 868 const int64_t metadata_id = put_metadata( 869 _pimpl->_db, test_case.get_metadata()); 870 871 sqlite::statement stmt = _pimpl->_db.create_statement( 872 "INSERT INTO test_cases (test_program_id, name, metadata_id) " 873 "VALUES (:test_program_id, :name, :metadata_id)"); 874 stmt.bind(":test_program_id", test_program_id); 875 stmt.bind(":name", test_case.name()); 876 stmt.bind(":metadata_id", metadata_id); 877 stmt.step_without_results(); 878 return _pimpl->_db.last_insert_rowid(); 879 } catch (const sqlite::error& e) { 880 throw error(e.what()); 881 } 882 } 883 884 885 /// Stores a file generated by a test case into the database as a BLOB. 886 /// 887 /// \param name The name of the file to store in the database. This needs to be 888 /// unique per test case. The caller is free to decide what names to use 889 /// for which files. For example, it might make sense to always call 890 /// __STDOUT__ the stdout of the test case so that it is easy to locate. 891 /// \param path The path to the file to be stored. 892 /// \param test_case_id The identifier of the test case this file belongs to. 893 /// 894 /// \return The identifier of the stored file, or none if the file was empty. 895 /// 896 /// \throw store::error If there are problems writing to the database. 897 optional< int64_t > 898 store::transaction::put_test_case_file(const std::string& name, 899 const fs::path& path, 900 const int64_t test_case_id) 901 { 902 LD(F("Storing %s (%s) of test case %s") % name % path % test_case_id); 903 try { 904 const optional< int64_t > file_id = put_file(_pimpl->_db, path); 905 if (!file_id) { 906 LD("Not storing empty file"); 907 return none; 908 } 909 910 sqlite::statement stmt = _pimpl->_db.create_statement( 911 "INSERT INTO test_case_files (test_case_id, file_name, file_id) " 912 "VALUES (:test_case_id, :file_name, :file_id)"); 913 stmt.bind(":test_case_id", test_case_id); 914 stmt.bind(":file_name", name); 915 stmt.bind(":file_id", file_id.get()); 916 stmt.step_without_results(); 917 918 return optional< int64_t >(_pimpl->_db.last_insert_rowid()); 919 } catch (const sqlite::error& e) { 920 throw error(e.what()); 921 } 922 } 923 924 925 /// Puts a result into the database. 926 /// 927 /// \pre The result has not been put yet. 928 /// \post The result is stored into the database with a new identifier. 929 /// 930 /// \param result The result to put. 931 /// \param test_case_id The test case this result corresponds to. 932 /// \param start_time The time when the test started to run. 933 /// \param end_time The time when the test finished running. 934 /// 935 /// \return The identifier of the inserted result. 936 /// 937 /// \throw error If there is any problem when talking to the database. 938 int64_t 939 store::transaction::put_result(const engine::test_result& result, 940 const int64_t test_case_id, 941 const datetime::timestamp& start_time, 942 const datetime::timestamp& end_time) 943 { 944 try { 945 sqlite::statement stmt = _pimpl->_db.create_statement( 946 "INSERT INTO test_results (test_case_id, result_type, " 947 " result_reason, start_time, " 948 " end_time) " 949 "VALUES (:test_case_id, :result_type, :result_reason, " 950 " :start_time, :end_time)"); 951 stmt.bind(":test_case_id", test_case_id); 952 953 switch (result.type()) { 954 case engine::test_result::broken: 955 stmt.bind(":result_type", "broken"); 956 break; 957 958 case engine::test_result::expected_failure: 959 stmt.bind(":result_type", "expected_failure"); 960 break; 961 962 case engine::test_result::failed: 963 stmt.bind(":result_type", "failed"); 964 break; 965 966 case engine::test_result::passed: 967 stmt.bind(":result_type", "passed"); 968 break; 969 970 case engine::test_result::skipped: 971 stmt.bind(":result_type", "skipped"); 972 break; 973 974 default: 975 UNREACHABLE; 976 } 977 978 if (result.reason().empty()) 979 stmt.bind(":result_reason", sqlite::null()); 980 else 981 stmt.bind(":result_reason", result.reason()); 982 983 store::bind_timestamp(stmt, ":start_time", start_time); 984 store::bind_timestamp(stmt, ":end_time", end_time); 985 986 stmt.step_without_results(); 987 const int64_t result_id = _pimpl->_db.last_insert_rowid(); 988 989 return result_id; 990 } catch (const sqlite::error& e) { 991 throw error(e.what()); 992 } 993 } 994