Path: blob/main/contrib/kyua/store/write_transaction_test.cpp
39478 views
// Copyright 2011 The Kyua Authors.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are5// met:6//7// * Redistributions of source code must retain the above copyright8// notice, this list of conditions and the following disclaimer.9// * Redistributions in binary form must reproduce the above copyright10// notice, this list of conditions and the following disclaimer in the11// documentation and/or other materials provided with the distribution.12// * Neither the name of Google Inc. nor the names of its contributors13// may be used to endorse or promote products derived from this software14// without specific prior written permission.15//16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2728#include "store/write_transaction.hpp"2930#include <cstring>31#include <map>32#include <string>3334#include <atf-c++.hpp>3536#include "model/context.hpp"37#include "model/metadata.hpp"38#include "model/test_case.hpp"39#include "model/test_program.hpp"40#include "model/test_result.hpp"41#include "store/exceptions.hpp"42#include "store/write_backend.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"5051namespace datetime = utils::datetime;52namespace fs = utils::fs;53namespace logging = utils::logging;54namespace sqlite = utils::sqlite;5556using utils::optional;575859namespace {606162/// Performs a test for a working put_result63///64/// \param result The result object to put.65/// \param result_type The textual name of the result to expect in the66/// database.67/// \param exp_reason The reason to expect in the database. This is separate68/// from the result parameter so that we can handle passed() here as well.69/// Just provide NULL in this case.70static void71do_put_result_ok_test(const model::test_result& result,72const char* result_type, const char* exp_reason)73{74store::write_backend backend = store::write_backend::open_rw(75fs::path("test.db"));76backend.database().exec("PRAGMA foreign_keys = OFF");77store::write_transaction tx = backend.start_write();78const datetime::timestamp start_time = datetime::timestamp::from_values(792012, 01, 30, 22, 10, 00, 0);80const datetime::timestamp end_time = datetime::timestamp::from_values(812012, 01, 30, 22, 15, 30, 123456);82tx.put_result(result, 312, start_time, end_time);83tx.commit();8485sqlite::statement stmt = backend.database().create_statement(86"SELECT test_case_id, result_type, result_reason "87"FROM test_results");8889ATF_REQUIRE(stmt.step());90ATF_REQUIRE_EQ(312, stmt.column_int64(0));91ATF_REQUIRE_EQ(result_type, stmt.column_text(1));92if (exp_reason != NULL)93ATF_REQUIRE_EQ(exp_reason, stmt.column_text(2));94else95ATF_REQUIRE(stmt.column_type(2) == sqlite::type_null);96ATF_REQUIRE(!stmt.step());97}9899100} // anonymous namespace101102103ATF_TEST_CASE(commit__ok);104ATF_TEST_CASE_HEAD(commit__ok)105{106logging::set_inmemory();107set_md_var("require.files", store::detail::schema_file().c_str());108}109ATF_TEST_CASE_BODY(commit__ok)110{111store::write_backend backend = store::write_backend::open_rw(112fs::path("test.db"));113store::write_transaction tx = backend.start_write();114backend.database().exec("CREATE TABLE a (b INTEGER PRIMARY KEY)");115backend.database().exec("SELECT * FROM a");116tx.commit();117backend.database().exec("SELECT * FROM a");118}119120121ATF_TEST_CASE(commit__fail);122ATF_TEST_CASE_HEAD(commit__fail)123{124logging::set_inmemory();125set_md_var("require.files", store::detail::schema_file().c_str());126}127ATF_TEST_CASE_BODY(commit__fail)128{129store::write_backend backend = store::write_backend::open_rw(130fs::path("test.db"));131const model::context context(fs::path("/foo/bar"),132std::map< std::string, std::string >());133{134store::write_transaction tx = backend.start_write();135tx.put_context(context);136backend.database().exec(137"CREATE TABLE foo ("138"a REFERENCES env_vars(var_name) DEFERRABLE INITIALLY DEFERRED)");139backend.database().exec("INSERT INTO foo VALUES (\"WHAT\")");140ATF_REQUIRE_THROW(store::error, tx.commit());141}142// If the code attempts to maintain any state regarding the already-put143// objects and the commit does not clean up correctly, this would fail in144// some manner.145store::write_transaction tx = backend.start_write();146tx.put_context(context);147tx.commit();148}149150151ATF_TEST_CASE(rollback__ok);152ATF_TEST_CASE_HEAD(rollback__ok)153{154logging::set_inmemory();155set_md_var("require.files", store::detail::schema_file().c_str());156}157ATF_TEST_CASE_BODY(rollback__ok)158{159store::write_backend backend = store::write_backend::open_rw(160fs::path("test.db"));161store::write_transaction tx = backend.start_write();162backend.database().exec("CREATE TABLE a_table (b INTEGER PRIMARY KEY)");163backend.database().exec("SELECT * FROM a_table");164tx.rollback();165ATF_REQUIRE_THROW_RE(sqlite::error, "a_table",166backend.database().exec("SELECT * FROM a_table"));167}168169170ATF_TEST_CASE(put_test_program__ok);171ATF_TEST_CASE_HEAD(put_test_program__ok)172{173logging::set_inmemory();174set_md_var("require.files", store::detail::schema_file().c_str());175}176ATF_TEST_CASE_BODY(put_test_program__ok)177{178const model::metadata md = model::metadata_builder()179.add_custom("var1", "value1")180.add_custom("var2", "value2")181.build();182const model::test_program test_program(183"mock", fs::path("the/binary"), fs::path("/some//root"),184"the-suite", md, model::test_cases_map());185186store::write_backend backend = store::write_backend::open_rw(187fs::path("test.db"));188backend.database().exec("PRAGMA foreign_keys = OFF");189store::write_transaction tx = backend.start_write();190const int64_t test_program_id = tx.put_test_program(test_program);191tx.commit();192193{194sqlite::statement stmt = backend.database().create_statement(195"SELECT * FROM test_programs");196197ATF_REQUIRE(stmt.step());198ATF_REQUIRE_EQ(test_program_id,199stmt.safe_column_int64("test_program_id"));200ATF_REQUIRE_EQ("/some/root/the/binary",201stmt.safe_column_text("absolute_path"));202ATF_REQUIRE_EQ("/some/root", stmt.safe_column_text("root"));203ATF_REQUIRE_EQ("the/binary", stmt.safe_column_text("relative_path"));204ATF_REQUIRE_EQ("the-suite", stmt.safe_column_text("test_suite_name"));205ATF_REQUIRE(!stmt.step());206}207}208209210ATF_TEST_CASE(put_test_case__fail);211ATF_TEST_CASE_HEAD(put_test_case__fail)212{213logging::set_inmemory();214set_md_var("require.files", store::detail::schema_file().c_str());215}216ATF_TEST_CASE_BODY(put_test_case__fail)217{218const model::test_program test_program = model::test_program_builder(219"plain", fs::path("the/binary"), fs::path("/some/root"), "the-suite")220.add_test_case("main")221.build();222223store::write_backend backend = store::write_backend::open_rw(224fs::path("test.db"));225store::write_transaction tx = backend.start_write();226ATF_REQUIRE_THROW(store::error, tx.put_test_case(test_program, "main", -1));227tx.commit();228}229230231ATF_TEST_CASE(put_test_case_file__empty);232ATF_TEST_CASE_HEAD(put_test_case_file__empty)233{234logging::set_inmemory();235set_md_var("require.files", store::detail::schema_file().c_str());236}237ATF_TEST_CASE_BODY(put_test_case_file__empty)238{239atf::utils::create_file("input.txt", "");240241store::write_backend backend = store::write_backend::open_rw(242fs::path("test.db"));243backend.database().exec("PRAGMA foreign_keys = OFF");244store::write_transaction tx = backend.start_write();245const optional< int64_t > file_id = tx.put_test_case_file(246"my-file", fs::path("input.txt"), 123L);247tx.commit();248ATF_REQUIRE(!file_id);249250sqlite::statement stmt = backend.database().create_statement(251"SELECT * FROM test_case_files NATURAL JOIN files");252ATF_REQUIRE(!stmt.step());253}254255256ATF_TEST_CASE(put_test_case_file__some);257ATF_TEST_CASE_HEAD(put_test_case_file__some)258{259logging::set_inmemory();260set_md_var("require.files", store::detail::schema_file().c_str());261}262ATF_TEST_CASE_BODY(put_test_case_file__some)263{264const char contents[] = "This is a test!";265266atf::utils::create_file("input.txt", contents);267268store::write_backend backend = store::write_backend::open_rw(269fs::path("test.db"));270backend.database().exec("PRAGMA foreign_keys = OFF");271store::write_transaction tx = backend.start_write();272const optional< int64_t > file_id = tx.put_test_case_file(273"my-file", fs::path("input.txt"), 123L);274tx.commit();275ATF_REQUIRE(file_id);276277sqlite::statement stmt = backend.database().create_statement(278"SELECT * FROM test_case_files NATURAL JOIN files");279280ATF_REQUIRE(stmt.step());281ATF_REQUIRE_EQ(123L, stmt.safe_column_int64("test_case_id"));282ATF_REQUIRE_EQ("my-file", stmt.safe_column_text("file_name"));283const sqlite::blob blob = stmt.safe_column_blob("contents");284ATF_REQUIRE(std::strlen(contents) == static_cast< std::size_t >(blob.size));285ATF_REQUIRE(std::memcmp(contents, blob.memory, blob.size) == 0);286ATF_REQUIRE(!stmt.step());287}288289290ATF_TEST_CASE(put_test_case_file__fail);291ATF_TEST_CASE_HEAD(put_test_case_file__fail)292{293logging::set_inmemory();294set_md_var("require.files", store::detail::schema_file().c_str());295}296ATF_TEST_CASE_BODY(put_test_case_file__fail)297{298store::write_backend backend = store::write_backend::open_rw(299fs::path("test.db"));300backend.database().exec("PRAGMA foreign_keys = OFF");301store::write_transaction tx = backend.start_write();302ATF_REQUIRE_THROW(store::error,303tx.put_test_case_file("foo", fs::path("missing"), 1L));304tx.commit();305306sqlite::statement stmt = backend.database().create_statement(307"SELECT * FROM test_case_files NATURAL JOIN files");308ATF_REQUIRE(!stmt.step());309}310311312ATF_TEST_CASE(put_result__ok__broken);313ATF_TEST_CASE_HEAD(put_result__ok__broken)314{315logging::set_inmemory();316set_md_var("require.files", store::detail::schema_file().c_str());317}318ATF_TEST_CASE_BODY(put_result__ok__broken)319{320const model::test_result result(model::test_result_broken, "a b cd");321do_put_result_ok_test(result, "broken", "a b cd");322}323324325ATF_TEST_CASE(put_result__ok__expected_failure);326ATF_TEST_CASE_HEAD(put_result__ok__expected_failure)327{328logging::set_inmemory();329set_md_var("require.files", store::detail::schema_file().c_str());330}331ATF_TEST_CASE_BODY(put_result__ok__expected_failure)332{333const model::test_result result(model::test_result_expected_failure,334"a b cd");335do_put_result_ok_test(result, "expected_failure", "a b cd");336}337338339ATF_TEST_CASE(put_result__ok__failed);340ATF_TEST_CASE_HEAD(put_result__ok__failed)341{342logging::set_inmemory();343set_md_var("require.files", store::detail::schema_file().c_str());344}345ATF_TEST_CASE_BODY(put_result__ok__failed)346{347const model::test_result result(model::test_result_failed, "a b cd");348do_put_result_ok_test(result, "failed", "a b cd");349}350351352ATF_TEST_CASE(put_result__ok__passed);353ATF_TEST_CASE_HEAD(put_result__ok__passed)354{355logging::set_inmemory();356set_md_var("require.files", store::detail::schema_file().c_str());357}358ATF_TEST_CASE_BODY(put_result__ok__passed)359{360const model::test_result result(model::test_result_passed);361do_put_result_ok_test(result, "passed", NULL);362}363364365ATF_TEST_CASE(put_result__ok__skipped);366ATF_TEST_CASE_HEAD(put_result__ok__skipped)367{368logging::set_inmemory();369set_md_var("require.files", store::detail::schema_file().c_str());370}371ATF_TEST_CASE_BODY(put_result__ok__skipped)372{373const model::test_result result(model::test_result_skipped, "a b cd");374do_put_result_ok_test(result, "skipped", "a b cd");375}376377378ATF_TEST_CASE(put_result__fail);379ATF_TEST_CASE_HEAD(put_result__fail)380{381logging::set_inmemory();382set_md_var("require.files", store::detail::schema_file().c_str());383}384ATF_TEST_CASE_BODY(put_result__fail)385{386const model::test_result result(model::test_result_broken, "foo");387388store::write_backend backend = store::write_backend::open_rw(389fs::path("test.db"));390store::write_transaction tx = backend.start_write();391const datetime::timestamp zero = datetime::timestamp::from_microseconds(0);392ATF_REQUIRE_THROW(store::error, tx.put_result(result, -1, zero, zero));393tx.commit();394}395396397ATF_INIT_TEST_CASES(tcs)398{399ATF_ADD_TEST_CASE(tcs, commit__ok);400ATF_ADD_TEST_CASE(tcs, commit__fail);401ATF_ADD_TEST_CASE(tcs, rollback__ok);402403ATF_ADD_TEST_CASE(tcs, put_test_program__ok);404ATF_ADD_TEST_CASE(tcs, put_test_case__fail);405ATF_ADD_TEST_CASE(tcs, put_test_case_file__empty);406ATF_ADD_TEST_CASE(tcs, put_test_case_file__some);407ATF_ADD_TEST_CASE(tcs, put_test_case_file__fail);408409ATF_ADD_TEST_CASE(tcs, put_result__ok__broken);410ATF_ADD_TEST_CASE(tcs, put_result__ok__expected_failure);411ATF_ADD_TEST_CASE(tcs, put_result__ok__failed);412ATF_ADD_TEST_CASE(tcs, put_result__ok__passed);413ATF_ADD_TEST_CASE(tcs, put_result__ok__skipped);414ATF_ADD_TEST_CASE(tcs, put_result__fail);415}416417418