Home | History | Annotate | Line # | Download | only in store
      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