| // Copyright 2019 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "arc/apk-cache/apk_cache_database_test_utils.h" |
| |
| #include <array> |
| #include <cinttypes> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include <base/files/file_path.h> |
| #include <base/strings/stringprintf.h> |
| #include <sqlite3.h> |
| |
| #include "arc/apk-cache/apk_cache_database.h" |
| |
| namespace apk_cache { |
| |
| namespace { |
| |
| constexpr std::array<const char*, 8> kCreateDatabaseSQL = { |
| "PRAGMA foreign_keys = off", |
| "CREATE TABLE sessions (" |
| " id INTEGER PRIMARY KEY AUTOINCREMENT" |
| " NOT NULL," |
| " source TEXT NOT NULL," |
| " timestamp INTEGER NOT NULL," |
| " attributes TEXT," |
| " status INTEGER NOT NULL" |
| ")", |
| "CREATE TABLE file_entries (" |
| " id INTEGER PRIMARY KEY AUTOINCREMENT" |
| " NOT NULL," |
| " package_name TEXT NOT NULL," |
| " version_code INTEGER NOT NULL," |
| " type TEXT NOT NULL," |
| " attributes TEXT," |
| " size INTEGER NOT NULL," |
| " hash TEXT," |
| " access_time INTEGER NOT NULL," |
| " priority INTEGER NOT NULL," |
| " session_id INTEGER NOT NULL," |
| " FOREIGN KEY (" |
| " session_id" |
| " )" |
| " REFERENCES sessions (id) ON UPDATE NO ACTION" |
| " ON DELETE CASCADE" |
| ")", |
| "CREATE INDEX index_hash ON file_entries (" |
| " hash" |
| ")", |
| "CREATE INDEX index_package_version_type ON file_entries (" |
| " package_name," |
| " version_code," |
| " type" |
| ")", |
| "CREATE INDEX index_session_id ON file_entries (" |
| " session_id" |
| ")", |
| "CREATE INDEX index_status ON sessions (" |
| " status" |
| ")", |
| "PRAGMA foreign_keys = on"}; |
| |
| int ExecSQL(const base::FilePath& db_path, |
| const std::vector<std::string>& sqls) { |
| sqlite3* db; |
| int result; |
| result = sqlite3_open(db_path.MaybeAsASCII().c_str(), &db); |
| std::unique_ptr<sqlite3, decltype(&sqlite3_close)> db_ptr(db, &sqlite3_close); |
| if (result != SQLITE_OK) |
| return result; |
| |
| for (const auto& sql : sqls) { |
| result = sqlite3_exec(db_ptr.get(), sql.c_str(), nullptr, nullptr, nullptr); |
| if (result != SQLITE_OK) |
| return result; |
| } |
| |
| return sqlite3_close(db_ptr.release()); |
| } |
| |
| } // namespace |
| |
| int CreateDatabaseForTesting(const base::FilePath& db_path) { |
| std::vector<std::string> create_db_sql(kCreateDatabaseSQL.begin(), |
| kCreateDatabaseSQL.end()); |
| return ExecSQL(db_path, create_db_sql); |
| } |
| |
| bool InsertSessionForTesting(const base::FilePath& db_path, |
| const Session& session) { |
| const std::string sql = base::StringPrintf( |
| "INSERT INTO sessions (id,source,timestamp,status) VALUES " |
| "(%" PRId64 ", '%s', %" PRId64 ", %" PRId32 ")", |
| session.id, EscapeSQLString(session.source).c_str(), |
| session.timestamp.ToJavaTime(), session.status); |
| return ExecSQL(db_path, {sql}) == SQLITE_OK; |
| } |
| |
| bool InsertFileEntryForTesting(const base::FilePath& db_path, |
| const FileEntry& file_entry) { |
| std::string attributes_in_sql; |
| if (file_entry.attributes) { |
| attributes_in_sql = base::StringPrintf( |
| "'%s'", EscapeSQLString(*(file_entry.attributes)).c_str()); |
| } else { |
| attributes_in_sql = "null"; |
| } |
| |
| std::string hash_in_sql; |
| if (file_entry.hash) { |
| hash_in_sql = |
| base::StringPrintf("'%s'", EscapeSQLString(*(file_entry.hash)).c_str()); |
| } else { |
| hash_in_sql = "null"; |
| } |
| |
| std::string sql = base::StringPrintf( |
| "INSERT INTO file_entries (id,package_name,version_code,type," |
| "attributes,size,hash,access_time,priority,session_id) VALUES" |
| "(%" PRId64 ", '%s', %" PRId64 ", '%s', %s, %" PRId64 ", %s, %" PRId64 |
| ", %" PRId32 ", %" PRId64 ")", |
| file_entry.id, EscapeSQLString(file_entry.package_name).c_str(), |
| file_entry.version_code, EscapeSQLString(file_entry.type).c_str(), |
| attributes_in_sql.c_str(), file_entry.size, hash_in_sql.c_str(), |
| file_entry.access_time.ToJavaTime(), file_entry.priority, |
| file_entry.session_id); |
| return ExecSQL(db_path, {sql}) == SQLITE_OK; |
| } |
| |
| bool UpdateSessionTimestampForTesting(const base::FilePath& db_path, |
| int64_t id, |
| const base::Time& timestamp) { |
| const std::string sql = base::StringPrintf( |
| "UPDATE sessions SET timestamp = %" PRId64 " WHERE id = %" PRId64, |
| timestamp.ToJavaTime(), id); |
| return ExecSQL(db_path, {sql}) == SQLITE_OK; |
| } |
| |
| bool UpdateSessionStatusForTesting(const base::FilePath& db_path, |
| int64_t id, |
| int32_t status) { |
| const std::string sql = base::StringPrintf( |
| "UPDATE sessions SET status = %" PRId32 " WHERE id = %" PRId64, status, |
| id); |
| return ExecSQL(db_path, {sql}) == SQLITE_OK; |
| } |
| |
| bool UpdateFileAccessTimeForTesting(const base::FilePath& db_path, |
| int64_t id, |
| const base::Time& access_time) { |
| const std::string sql = base::StringPrintf( |
| "UPDATE file_entries SET access_time = %" PRId64 " WHERE id = %" PRId64, |
| access_time.ToJavaTime(), id); |
| return ExecSQL(db_path, {sql}) == SQLITE_OK; |
| } |
| |
| bool DeleteFilesOfTypeForTesting(const base::FilePath& db_path, |
| const std::string& package_name, |
| int64_t version_code, |
| const std::string& type) { |
| const std::string sql = base::StringPrintf( |
| "DELETE FROM file_entries WHERE package_name = '%s'" |
| " AND version_code = %" PRId64 " AND type = '%s'", |
| EscapeSQLString(package_name).c_str(), version_code, |
| EscapeSQLString(type).c_str()); |
| return ExecSQL(db_path, {sql}) == SQLITE_OK; |
| } |
| |
| } // namespace apk_cache |