1 1.1 jmmv // Copyright 2011 Google Inc. 2 1.1 jmmv // All rights reserved. 3 1.1 jmmv // 4 1.1 jmmv // Redistribution and use in source and binary forms, with or without 5 1.1 jmmv // modification, are permitted provided that the following conditions are 6 1.1 jmmv // met: 7 1.1 jmmv // 8 1.1 jmmv // * Redistributions of source code must retain the above copyright 9 1.1 jmmv // notice, this list of conditions and the following disclaimer. 10 1.1 jmmv // * Redistributions in binary form must reproduce the above copyright 11 1.1 jmmv // notice, this list of conditions and the following disclaimer in the 12 1.1 jmmv // documentation and/or other materials provided with the distribution. 13 1.1 jmmv // * Neither the name of Google Inc. nor the names of its contributors 14 1.1 jmmv // may be used to endorse or promote products derived from this software 15 1.1 jmmv // without specific prior written permission. 16 1.1 jmmv // 17 1.1 jmmv // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 1.1 jmmv // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 1.1 jmmv // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 1.1 jmmv // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 1.1 jmmv // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 1.1 jmmv // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 1.1 jmmv // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 jmmv // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 jmmv // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 jmmv // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 1.1 jmmv // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 jmmv 29 1.1 jmmv #include "store/backend.hpp" 30 1.1 jmmv 31 1.1 jmmv extern "C" { 32 1.1 jmmv #include <sys/stat.h> 33 1.1 jmmv } 34 1.1 jmmv 35 1.1 jmmv #include <atf-c++.hpp> 36 1.1 jmmv 37 1.1 jmmv #include "store/exceptions.hpp" 38 1.1 jmmv #include "store/metadata.hpp" 39 1.1 jmmv #include "utils/datetime.hpp" 40 1.1 jmmv #include "utils/env.hpp" 41 1.1 jmmv #include "utils/fs/operations.hpp" 42 1.1 jmmv #include "utils/fs/path.hpp" 43 1.1 jmmv #include "utils/logging/operations.hpp" 44 1.1 jmmv #include "utils/sqlite/database.hpp" 45 1.1 jmmv #include "utils/sqlite/statement.ipp" 46 1.1 jmmv 47 1.1 jmmv namespace datetime = utils::datetime; 48 1.1 jmmv namespace fs = utils::fs; 49 1.1 jmmv namespace logging = utils::logging; 50 1.1 jmmv namespace sqlite = utils::sqlite; 51 1.1 jmmv 52 1.1 jmmv 53 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__backup_database__ok); 54 1.1 jmmv ATF_TEST_CASE_BODY(detail__backup_database__ok) 55 1.1 jmmv { 56 1.1 jmmv atf::utils::create_file("test.db", "The DB\n"); 57 1.1 jmmv store::detail::backup_database(fs::path("test.db"), 13); 58 1.1 jmmv ATF_REQUIRE(fs::exists(fs::path("test.db"))); 59 1.1 jmmv ATF_REQUIRE(fs::exists(fs::path("test.db.v13.backup"))); 60 1.1 jmmv ATF_REQUIRE(atf::utils::compare_file("test.db.v13.backup", "The DB\n")); 61 1.1 jmmv } 62 1.1 jmmv 63 1.1 jmmv 64 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__backup_database__ok_overwrite); 65 1.1 jmmv ATF_TEST_CASE_BODY(detail__backup_database__ok_overwrite) 66 1.1 jmmv { 67 1.1 jmmv atf::utils::create_file("test.db", "Original contents"); 68 1.1 jmmv atf::utils::create_file("test.db.v1.backup", "Overwrite me"); 69 1.1 jmmv store::detail::backup_database(fs::path("test.db"), 1); 70 1.1 jmmv ATF_REQUIRE(fs::exists(fs::path("test.db"))); 71 1.1 jmmv ATF_REQUIRE(fs::exists(fs::path("test.db.v1.backup"))); 72 1.1 jmmv ATF_REQUIRE(atf::utils::compare_file("test.db.v1.backup", 73 1.1 jmmv "Original contents")); 74 1.1 jmmv } 75 1.1 jmmv 76 1.1 jmmv 77 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__backup_database__fail_open); 78 1.1 jmmv ATF_TEST_CASE_BODY(detail__backup_database__fail_open) 79 1.1 jmmv { 80 1.1 jmmv ATF_REQUIRE_THROW_RE(store::error, "Cannot open.*foo.db", 81 1.1 jmmv store::detail::backup_database(fs::path("foo.db"), 5)); 82 1.1 jmmv } 83 1.1 jmmv 84 1.1 jmmv 85 1.1 jmmv ATF_TEST_CASE(detail__backup_database__fail_create); 86 1.1 jmmv ATF_TEST_CASE_HEAD(detail__backup_database__fail_create) 87 1.1 jmmv { 88 1.1 jmmv set_md_var("require.user", "unprivileged"); 89 1.1 jmmv } 90 1.1 jmmv ATF_TEST_CASE_BODY(detail__backup_database__fail_create) 91 1.1 jmmv { 92 1.1 jmmv ATF_REQUIRE(::mkdir("dir", 0755) != -1); 93 1.1 jmmv atf::utils::create_file("dir/test.db", "Does not need to be valid"); 94 1.1 jmmv ATF_REQUIRE(::chmod("dir", 0111) != -1); 95 1.1 jmmv ATF_REQUIRE_THROW_RE( 96 1.1 jmmv store::error, "Cannot create.*dir/test.db.v13.backup", 97 1.1 jmmv store::detail::backup_database(fs::path("dir/test.db"), 13)); 98 1.1 jmmv } 99 1.1 jmmv 100 1.1 jmmv 101 1.1 jmmv ATF_TEST_CASE(detail__initialize__ok); 102 1.1 jmmv ATF_TEST_CASE_HEAD(detail__initialize__ok) 103 1.1 jmmv { 104 1.1 jmmv logging::set_inmemory(); 105 1.1 jmmv set_md_var("require.files", store::detail::schema_file().c_str()); 106 1.1 jmmv } 107 1.1 jmmv ATF_TEST_CASE_BODY(detail__initialize__ok) 108 1.1 jmmv { 109 1.1 jmmv sqlite::database db = sqlite::database::in_memory(); 110 1.1 jmmv const datetime::timestamp before = datetime::timestamp::now(); 111 1.1 jmmv const store::metadata md = store::detail::initialize(db); 112 1.1 jmmv const datetime::timestamp after = datetime::timestamp::now(); 113 1.1 jmmv 114 1.1 jmmv ATF_REQUIRE(md.timestamp() >= before.to_seconds()); 115 1.1 jmmv ATF_REQUIRE(md.timestamp() <= after.to_microseconds()); 116 1.1 jmmv ATF_REQUIRE_EQ(store::detail::current_schema_version, md.schema_version()); 117 1.1 jmmv 118 1.1 jmmv // Query some known tables to ensure they were created. 119 1.1 jmmv db.exec("SELECT * FROM metadata"); 120 1.1 jmmv 121 1.1 jmmv // And now query some know values. 122 1.1 jmmv sqlite::statement stmt = db.create_statement( 123 1.1 jmmv "SELECT COUNT(*) FROM metadata"); 124 1.1 jmmv ATF_REQUIRE(stmt.step()); 125 1.1 jmmv ATF_REQUIRE_EQ(1, stmt.column_int(0)); 126 1.1 jmmv ATF_REQUIRE(!stmt.step()); 127 1.1 jmmv } 128 1.1 jmmv 129 1.1 jmmv 130 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__initialize__missing_schema); 131 1.1 jmmv ATF_TEST_CASE_BODY(detail__initialize__missing_schema) 132 1.1 jmmv { 133 1.1 jmmv utils::setenv("KYUA_STOREDIR", "/non-existent"); 134 1.1 jmmv store::detail::current_schema_version = 712; 135 1.1 jmmv 136 1.1 jmmv sqlite::database db = sqlite::database::in_memory(); 137 1.1 jmmv ATF_REQUIRE_THROW_RE(store::error, 138 1.1 jmmv "Cannot open.*'/non-existent/schema_v712.sql'", 139 1.1 jmmv store::detail::initialize(db)); 140 1.1 jmmv } 141 1.1 jmmv 142 1.1 jmmv 143 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__initialize__sqlite_error); 144 1.1 jmmv ATF_TEST_CASE_BODY(detail__initialize__sqlite_error) 145 1.1 jmmv { 146 1.1 jmmv utils::setenv("KYUA_STOREDIR", "."); 147 1.1 jmmv store::detail::current_schema_version = 712; 148 1.1 jmmv 149 1.1 jmmv atf::utils::create_file("schema_v712.sql", "foo_bar_baz;\n"); 150 1.1 jmmv 151 1.1 jmmv sqlite::database db = sqlite::database::in_memory(); 152 1.1 jmmv ATF_REQUIRE_THROW_RE(store::error, "Failed to initialize.*:.*foo_bar_baz", 153 1.1 jmmv store::detail::initialize(db)); 154 1.1 jmmv } 155 1.1 jmmv 156 1.1 jmmv 157 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__migration_file__builtin); 158 1.1 jmmv ATF_TEST_CASE_BODY(detail__migration_file__builtin) 159 1.1 jmmv { 160 1.1 jmmv utils::unsetenv("KYUA_STOREDIR"); 161 1.1 jmmv ATF_REQUIRE_EQ(fs::path(KYUA_STOREDIR) / "migrate_v5_v9.sql", 162 1.1 jmmv store::detail::migration_file(5, 9)); 163 1.1 jmmv } 164 1.1 jmmv 165 1.1 jmmv 166 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__migration_file__overriden); 167 1.1 jmmv ATF_TEST_CASE_BODY(detail__migration_file__overriden) 168 1.1 jmmv { 169 1.1 jmmv utils::setenv("KYUA_STOREDIR", "/tmp/test"); 170 1.1 jmmv ATF_REQUIRE_EQ(fs::path("/tmp/test/migrate_v5_v9.sql"), 171 1.1 jmmv store::detail::migration_file(5, 9)); 172 1.1 jmmv } 173 1.1 jmmv 174 1.1 jmmv 175 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__schema_file__builtin); 176 1.1 jmmv ATF_TEST_CASE_BODY(detail__schema_file__builtin) 177 1.1 jmmv { 178 1.1 jmmv utils::unsetenv("KYUA_STOREDIR"); 179 1.1 jmmv ATF_REQUIRE_EQ(fs::path(KYUA_STOREDIR) / "schema_v2.sql", 180 1.1 jmmv store::detail::schema_file()); 181 1.1 jmmv } 182 1.1 jmmv 183 1.1 jmmv 184 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__schema_file__overriden); 185 1.1 jmmv ATF_TEST_CASE_BODY(detail__schema_file__overriden) 186 1.1 jmmv { 187 1.1 jmmv utils::setenv("KYUA_STOREDIR", "/tmp/test"); 188 1.1 jmmv store::detail::current_schema_version = 123; 189 1.1 jmmv ATF_REQUIRE_EQ(fs::path("/tmp/test/schema_v123.sql"), 190 1.1 jmmv store::detail::schema_file()); 191 1.1 jmmv } 192 1.1 jmmv 193 1.1 jmmv 194 1.1 jmmv ATF_TEST_CASE(backend__open_ro__ok); 195 1.1 jmmv ATF_TEST_CASE_HEAD(backend__open_ro__ok) 196 1.1 jmmv { 197 1.1 jmmv logging::set_inmemory(); 198 1.1 jmmv set_md_var("require.files", store::detail::schema_file().c_str()); 199 1.1 jmmv } 200 1.1 jmmv ATF_TEST_CASE_BODY(backend__open_ro__ok) 201 1.1 jmmv { 202 1.1 jmmv { 203 1.1 jmmv sqlite::database db = sqlite::database::open( 204 1.1 jmmv fs::path("test.db"), sqlite::open_readwrite | sqlite::open_create); 205 1.1 jmmv store::detail::initialize(db); 206 1.1 jmmv } 207 1.1 jmmv store::backend backend = store::backend::open_ro(fs::path("test.db")); 208 1.1 jmmv backend.database().exec("SELECT * FROM metadata"); 209 1.1 jmmv } 210 1.1 jmmv 211 1.1 jmmv 212 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(backend__open_ro__missing_file); 213 1.1 jmmv ATF_TEST_CASE_BODY(backend__open_ro__missing_file) 214 1.1 jmmv { 215 1.1 jmmv ATF_REQUIRE_THROW_RE(store::error, "Cannot open 'missing.db': ", 216 1.1 jmmv store::backend::open_ro(fs::path("missing.db"))); 217 1.1 jmmv ATF_REQUIRE(!fs::exists(fs::path("missing.db"))); 218 1.1 jmmv } 219 1.1 jmmv 220 1.1 jmmv 221 1.1 jmmv ATF_TEST_CASE(backend__open_ro__integrity_error); 222 1.1 jmmv ATF_TEST_CASE_HEAD(backend__open_ro__integrity_error) 223 1.1 jmmv { 224 1.1 jmmv logging::set_inmemory(); 225 1.1 jmmv set_md_var("require.files", store::detail::schema_file().c_str()); 226 1.1 jmmv } 227 1.1 jmmv ATF_TEST_CASE_BODY(backend__open_ro__integrity_error) 228 1.1 jmmv { 229 1.1 jmmv { 230 1.1 jmmv sqlite::database db = sqlite::database::open( 231 1.1 jmmv fs::path("test.db"), sqlite::open_readwrite | sqlite::open_create); 232 1.1 jmmv store::detail::initialize(db); 233 1.1 jmmv db.exec("DELETE FROM metadata"); 234 1.1 jmmv } 235 1.1 jmmv ATF_REQUIRE_THROW_RE(store::integrity_error, "metadata.*empty", 236 1.1 jmmv store::backend::open_ro(fs::path("test.db"))); 237 1.1 jmmv } 238 1.1 jmmv 239 1.1 jmmv 240 1.1 jmmv ATF_TEST_CASE(backend__open_rw__ok); 241 1.1 jmmv ATF_TEST_CASE_HEAD(backend__open_rw__ok) 242 1.1 jmmv { 243 1.1 jmmv logging::set_inmemory(); 244 1.1 jmmv set_md_var("require.files", store::detail::schema_file().c_str()); 245 1.1 jmmv } 246 1.1 jmmv ATF_TEST_CASE_BODY(backend__open_rw__ok) 247 1.1 jmmv { 248 1.1 jmmv { 249 1.1 jmmv sqlite::database db = sqlite::database::open( 250 1.1 jmmv fs::path("test.db"), sqlite::open_readwrite | sqlite::open_create); 251 1.1 jmmv store::detail::initialize(db); 252 1.1 jmmv } 253 1.1 jmmv store::backend backend = store::backend::open_rw(fs::path("test.db")); 254 1.1 jmmv backend.database().exec("SELECT * FROM metadata"); 255 1.1 jmmv } 256 1.1 jmmv 257 1.1 jmmv 258 1.1 jmmv ATF_TEST_CASE(backend__open_rw__create_missing); 259 1.1 jmmv ATF_TEST_CASE_HEAD(backend__open_rw__create_missing) 260 1.1 jmmv { 261 1.1 jmmv logging::set_inmemory(); 262 1.1 jmmv set_md_var("require.files", store::detail::schema_file().c_str()); 263 1.1 jmmv } 264 1.1 jmmv ATF_TEST_CASE_BODY(backend__open_rw__create_missing) 265 1.1 jmmv { 266 1.1 jmmv store::backend backend = store::backend::open_rw(fs::path("test.db")); 267 1.1 jmmv backend.database().exec("SELECT * FROM metadata"); 268 1.1 jmmv } 269 1.1 jmmv 270 1.1 jmmv 271 1.1 jmmv ATF_TEST_CASE(backend__open_rw__integrity_error); 272 1.1 jmmv ATF_TEST_CASE_HEAD(backend__open_rw__integrity_error) 273 1.1 jmmv { 274 1.1 jmmv logging::set_inmemory(); 275 1.1 jmmv set_md_var("require.files", store::detail::schema_file().c_str()); 276 1.1 jmmv } 277 1.1 jmmv ATF_TEST_CASE_BODY(backend__open_rw__integrity_error) 278 1.1 jmmv { 279 1.1 jmmv { 280 1.1 jmmv sqlite::database db = sqlite::database::open( 281 1.1 jmmv fs::path("test.db"), sqlite::open_readwrite | sqlite::open_create); 282 1.1 jmmv store::detail::initialize(db); 283 1.1 jmmv db.exec("DELETE FROM metadata"); 284 1.1 jmmv } 285 1.1 jmmv ATF_REQUIRE_THROW_RE(store::integrity_error, "metadata.*empty", 286 1.1 jmmv store::backend::open_rw(fs::path("test.db"))); 287 1.1 jmmv } 288 1.1 jmmv 289 1.1 jmmv 290 1.1 jmmv ATF_INIT_TEST_CASES(tcs) 291 1.1 jmmv { 292 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__backup_database__ok); 293 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__backup_database__ok_overwrite); 294 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__backup_database__fail_open); 295 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__backup_database__fail_create); 296 1.1 jmmv 297 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__initialize__ok); 298 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__initialize__missing_schema); 299 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__initialize__sqlite_error); 300 1.1 jmmv 301 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__migration_file__builtin); 302 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__migration_file__overriden); 303 1.1 jmmv 304 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__schema_file__builtin); 305 1.1 jmmv ATF_ADD_TEST_CASE(tcs, detail__schema_file__overriden); 306 1.1 jmmv 307 1.1 jmmv ATF_ADD_TEST_CASE(tcs, backend__open_ro__ok); 308 1.1 jmmv ATF_ADD_TEST_CASE(tcs, backend__open_ro__missing_file); 309 1.1 jmmv ATF_ADD_TEST_CASE(tcs, backend__open_ro__integrity_error); 310 1.1 jmmv ATF_ADD_TEST_CASE(tcs, backend__open_rw__ok); 311 1.1 jmmv ATF_ADD_TEST_CASE(tcs, backend__open_rw__create_missing); 312 1.1 jmmv ATF_ADD_TEST_CASE(tcs, backend__open_rw__integrity_error); 313 1.1 jmmv 314 1.1 jmmv // Tests for migrate_schema are in schema_inttest. This is because, for 315 1.1 jmmv // such tests to be meaningful, they need to be integration tests and don't 316 1.1 jmmv // really fit the goal of this unit-test module. 317 1.1 jmmv } 318