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/backend.hpp" 30 31 extern "C" { 32 #include <sys/stat.h> 33 } 34 35 #include <atf-c++.hpp> 36 37 #include "store/exceptions.hpp" 38 #include "store/metadata.hpp" 39 #include "utils/datetime.hpp" 40 #include "utils/env.hpp" 41 #include "utils/fs/operations.hpp" 42 #include "utils/fs/path.hpp" 43 #include "utils/logging/operations.hpp" 44 #include "utils/sqlite/database.hpp" 45 #include "utils/sqlite/statement.ipp" 46 47 namespace datetime = utils::datetime; 48 namespace fs = utils::fs; 49 namespace logging = utils::logging; 50 namespace sqlite = utils::sqlite; 51 52 53 ATF_TEST_CASE_WITHOUT_HEAD(detail__backup_database__ok); 54 ATF_TEST_CASE_BODY(detail__backup_database__ok) 55 { 56 atf::utils::create_file("test.db", "The DB\n"); 57 store::detail::backup_database(fs::path("test.db"), 13); 58 ATF_REQUIRE(fs::exists(fs::path("test.db"))); 59 ATF_REQUIRE(fs::exists(fs::path("test.db.v13.backup"))); 60 ATF_REQUIRE(atf::utils::compare_file("test.db.v13.backup", "The DB\n")); 61 } 62 63 64 ATF_TEST_CASE_WITHOUT_HEAD(detail__backup_database__ok_overwrite); 65 ATF_TEST_CASE_BODY(detail__backup_database__ok_overwrite) 66 { 67 atf::utils::create_file("test.db", "Original contents"); 68 atf::utils::create_file("test.db.v1.backup", "Overwrite me"); 69 store::detail::backup_database(fs::path("test.db"), 1); 70 ATF_REQUIRE(fs::exists(fs::path("test.db"))); 71 ATF_REQUIRE(fs::exists(fs::path("test.db.v1.backup"))); 72 ATF_REQUIRE(atf::utils::compare_file("test.db.v1.backup", 73 "Original contents")); 74 } 75 76 77 ATF_TEST_CASE_WITHOUT_HEAD(detail__backup_database__fail_open); 78 ATF_TEST_CASE_BODY(detail__backup_database__fail_open) 79 { 80 ATF_REQUIRE_THROW_RE(store::error, "Cannot open.*foo.db", 81 store::detail::backup_database(fs::path("foo.db"), 5)); 82 } 83 84 85 ATF_TEST_CASE(detail__backup_database__fail_create); 86 ATF_TEST_CASE_HEAD(detail__backup_database__fail_create) 87 { 88 set_md_var("require.user", "unprivileged"); 89 } 90 ATF_TEST_CASE_BODY(detail__backup_database__fail_create) 91 { 92 ATF_REQUIRE(::mkdir("dir", 0755) != -1); 93 atf::utils::create_file("dir/test.db", "Does not need to be valid"); 94 ATF_REQUIRE(::chmod("dir", 0111) != -1); 95 ATF_REQUIRE_THROW_RE( 96 store::error, "Cannot create.*dir/test.db.v13.backup", 97 store::detail::backup_database(fs::path("dir/test.db"), 13)); 98 } 99 100 101 ATF_TEST_CASE(detail__initialize__ok); 102 ATF_TEST_CASE_HEAD(detail__initialize__ok) 103 { 104 logging::set_inmemory(); 105 set_md_var("require.files", store::detail::schema_file().c_str()); 106 } 107 ATF_TEST_CASE_BODY(detail__initialize__ok) 108 { 109 sqlite::database db = sqlite::database::in_memory(); 110 const datetime::timestamp before = datetime::timestamp::now(); 111 const store::metadata md = store::detail::initialize(db); 112 const datetime::timestamp after = datetime::timestamp::now(); 113 114 ATF_REQUIRE(md.timestamp() >= before.to_seconds()); 115 ATF_REQUIRE(md.timestamp() <= after.to_microseconds()); 116 ATF_REQUIRE_EQ(store::detail::current_schema_version, md.schema_version()); 117 118 // Query some known tables to ensure they were created. 119 db.exec("SELECT * FROM metadata"); 120 121 // And now query some know values. 122 sqlite::statement stmt = db.create_statement( 123 "SELECT COUNT(*) FROM metadata"); 124 ATF_REQUIRE(stmt.step()); 125 ATF_REQUIRE_EQ(1, stmt.column_int(0)); 126 ATF_REQUIRE(!stmt.step()); 127 } 128 129 130 ATF_TEST_CASE_WITHOUT_HEAD(detail__initialize__missing_schema); 131 ATF_TEST_CASE_BODY(detail__initialize__missing_schema) 132 { 133 utils::setenv("KYUA_STOREDIR", "/non-existent"); 134 store::detail::current_schema_version = 712; 135 136 sqlite::database db = sqlite::database::in_memory(); 137 ATF_REQUIRE_THROW_RE(store::error, 138 "Cannot open.*'/non-existent/schema_v712.sql'", 139 store::detail::initialize(db)); 140 } 141 142 143 ATF_TEST_CASE_WITHOUT_HEAD(detail__initialize__sqlite_error); 144 ATF_TEST_CASE_BODY(detail__initialize__sqlite_error) 145 { 146 utils::setenv("KYUA_STOREDIR", "."); 147 store::detail::current_schema_version = 712; 148 149 atf::utils::create_file("schema_v712.sql", "foo_bar_baz;\n"); 150 151 sqlite::database db = sqlite::database::in_memory(); 152 ATF_REQUIRE_THROW_RE(store::error, "Failed to initialize.*:.*foo_bar_baz", 153 store::detail::initialize(db)); 154 } 155 156 157 ATF_TEST_CASE_WITHOUT_HEAD(detail__migration_file__builtin); 158 ATF_TEST_CASE_BODY(detail__migration_file__builtin) 159 { 160 utils::unsetenv("KYUA_STOREDIR"); 161 ATF_REQUIRE_EQ(fs::path(KYUA_STOREDIR) / "migrate_v5_v9.sql", 162 store::detail::migration_file(5, 9)); 163 } 164 165 166 ATF_TEST_CASE_WITHOUT_HEAD(detail__migration_file__overriden); 167 ATF_TEST_CASE_BODY(detail__migration_file__overriden) 168 { 169 utils::setenv("KYUA_STOREDIR", "/tmp/test"); 170 ATF_REQUIRE_EQ(fs::path("/tmp/test/migrate_v5_v9.sql"), 171 store::detail::migration_file(5, 9)); 172 } 173 174 175 ATF_TEST_CASE_WITHOUT_HEAD(detail__schema_file__builtin); 176 ATF_TEST_CASE_BODY(detail__schema_file__builtin) 177 { 178 utils::unsetenv("KYUA_STOREDIR"); 179 ATF_REQUIRE_EQ(fs::path(KYUA_STOREDIR) / "schema_v2.sql", 180 store::detail::schema_file()); 181 } 182 183 184 ATF_TEST_CASE_WITHOUT_HEAD(detail__schema_file__overriden); 185 ATF_TEST_CASE_BODY(detail__schema_file__overriden) 186 { 187 utils::setenv("KYUA_STOREDIR", "/tmp/test"); 188 store::detail::current_schema_version = 123; 189 ATF_REQUIRE_EQ(fs::path("/tmp/test/schema_v123.sql"), 190 store::detail::schema_file()); 191 } 192 193 194 ATF_TEST_CASE(backend__open_ro__ok); 195 ATF_TEST_CASE_HEAD(backend__open_ro__ok) 196 { 197 logging::set_inmemory(); 198 set_md_var("require.files", store::detail::schema_file().c_str()); 199 } 200 ATF_TEST_CASE_BODY(backend__open_ro__ok) 201 { 202 { 203 sqlite::database db = sqlite::database::open( 204 fs::path("test.db"), sqlite::open_readwrite | sqlite::open_create); 205 store::detail::initialize(db); 206 } 207 store::backend backend = store::backend::open_ro(fs::path("test.db")); 208 backend.database().exec("SELECT * FROM metadata"); 209 } 210 211 212 ATF_TEST_CASE_WITHOUT_HEAD(backend__open_ro__missing_file); 213 ATF_TEST_CASE_BODY(backend__open_ro__missing_file) 214 { 215 ATF_REQUIRE_THROW_RE(store::error, "Cannot open 'missing.db': ", 216 store::backend::open_ro(fs::path("missing.db"))); 217 ATF_REQUIRE(!fs::exists(fs::path("missing.db"))); 218 } 219 220 221 ATF_TEST_CASE(backend__open_ro__integrity_error); 222 ATF_TEST_CASE_HEAD(backend__open_ro__integrity_error) 223 { 224 logging::set_inmemory(); 225 set_md_var("require.files", store::detail::schema_file().c_str()); 226 } 227 ATF_TEST_CASE_BODY(backend__open_ro__integrity_error) 228 { 229 { 230 sqlite::database db = sqlite::database::open( 231 fs::path("test.db"), sqlite::open_readwrite | sqlite::open_create); 232 store::detail::initialize(db); 233 db.exec("DELETE FROM metadata"); 234 } 235 ATF_REQUIRE_THROW_RE(store::integrity_error, "metadata.*empty", 236 store::backend::open_ro(fs::path("test.db"))); 237 } 238 239 240 ATF_TEST_CASE(backend__open_rw__ok); 241 ATF_TEST_CASE_HEAD(backend__open_rw__ok) 242 { 243 logging::set_inmemory(); 244 set_md_var("require.files", store::detail::schema_file().c_str()); 245 } 246 ATF_TEST_CASE_BODY(backend__open_rw__ok) 247 { 248 { 249 sqlite::database db = sqlite::database::open( 250 fs::path("test.db"), sqlite::open_readwrite | sqlite::open_create); 251 store::detail::initialize(db); 252 } 253 store::backend backend = store::backend::open_rw(fs::path("test.db")); 254 backend.database().exec("SELECT * FROM metadata"); 255 } 256 257 258 ATF_TEST_CASE(backend__open_rw__create_missing); 259 ATF_TEST_CASE_HEAD(backend__open_rw__create_missing) 260 { 261 logging::set_inmemory(); 262 set_md_var("require.files", store::detail::schema_file().c_str()); 263 } 264 ATF_TEST_CASE_BODY(backend__open_rw__create_missing) 265 { 266 store::backend backend = store::backend::open_rw(fs::path("test.db")); 267 backend.database().exec("SELECT * FROM metadata"); 268 } 269 270 271 ATF_TEST_CASE(backend__open_rw__integrity_error); 272 ATF_TEST_CASE_HEAD(backend__open_rw__integrity_error) 273 { 274 logging::set_inmemory(); 275 set_md_var("require.files", store::detail::schema_file().c_str()); 276 } 277 ATF_TEST_CASE_BODY(backend__open_rw__integrity_error) 278 { 279 { 280 sqlite::database db = sqlite::database::open( 281 fs::path("test.db"), sqlite::open_readwrite | sqlite::open_create); 282 store::detail::initialize(db); 283 db.exec("DELETE FROM metadata"); 284 } 285 ATF_REQUIRE_THROW_RE(store::integrity_error, "metadata.*empty", 286 store::backend::open_rw(fs::path("test.db"))); 287 } 288 289 290 ATF_INIT_TEST_CASES(tcs) 291 { 292 ATF_ADD_TEST_CASE(tcs, detail__backup_database__ok); 293 ATF_ADD_TEST_CASE(tcs, detail__backup_database__ok_overwrite); 294 ATF_ADD_TEST_CASE(tcs, detail__backup_database__fail_open); 295 ATF_ADD_TEST_CASE(tcs, detail__backup_database__fail_create); 296 297 ATF_ADD_TEST_CASE(tcs, detail__initialize__ok); 298 ATF_ADD_TEST_CASE(tcs, detail__initialize__missing_schema); 299 ATF_ADD_TEST_CASE(tcs, detail__initialize__sqlite_error); 300 301 ATF_ADD_TEST_CASE(tcs, detail__migration_file__builtin); 302 ATF_ADD_TEST_CASE(tcs, detail__migration_file__overriden); 303 304 ATF_ADD_TEST_CASE(tcs, detail__schema_file__builtin); 305 ATF_ADD_TEST_CASE(tcs, detail__schema_file__overriden); 306 307 ATF_ADD_TEST_CASE(tcs, backend__open_ro__ok); 308 ATF_ADD_TEST_CASE(tcs, backend__open_ro__missing_file); 309 ATF_ADD_TEST_CASE(tcs, backend__open_ro__integrity_error); 310 ATF_ADD_TEST_CASE(tcs, backend__open_rw__ok); 311 ATF_ADD_TEST_CASE(tcs, backend__open_rw__create_missing); 312 ATF_ADD_TEST_CASE(tcs, backend__open_rw__integrity_error); 313 314 // Tests for migrate_schema are in schema_inttest. This is because, for 315 // such tests to be meaningful, they need to be integration tests and don't 316 // really fit the goal of this unit-test module. 317 } 318