Commit ac787363 authored by ckitagawa's avatar ckitagawa Committed by Commit Bot

[Paint Preview] File Manager

This CL introduces a FileManager class for managing the top level
paint_preview/ directory and the immediate per-url subdirectories.
All creation/deletion of these directories should occur through this
class. However, files within the per-url subdirectories can be modified
by any component of paint_preview (primarily the capture and
compositing code).

This class will be an integral component of a higher level manager
class. The manager will call into this class when it needs to perform
a capture or do deletion.

Bug: 1010042
Change-Id: I7b45a8f730837fcc1d0262ab0dcf3c89698974f8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1833289
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Reviewed-by: default avatarIan Vollick <vollick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#701702}
parent 9503034e
...@@ -241,6 +241,7 @@ test("components_unittests") { ...@@ -241,6 +241,7 @@ test("components_unittests") {
"//components/page_image_annotation/core:unit_tests", "//components/page_image_annotation/core:unit_tests",
"//components/page_load_metrics/browser:unit_tests", "//components/page_load_metrics/browser:unit_tests",
"//components/page_load_metrics/renderer:unit_tests", "//components/page_load_metrics/renderer:unit_tests",
"//components/paint_preview/browser:unit_tests",
"//components/paint_preview/common:unit_tests", "//components/paint_preview/common:unit_tests",
"//components/password_manager/content/browser:unit_tests", "//components/password_manager/content/browser:unit_tests",
"//components/payments/content:unit_tests", "//components/payments/content:unit_tests",
......
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//testing/test.gni")
if (!is_ios) {
static_library("browser") {
sources = [
"file_manager.cc",
"file_manager.h",
]
deps = [
"//base",
"//url",
]
}
source_set("unit_tests") {
testonly = true
sources = [
"file_manager_unittest.cc",
]
deps = [
":browser",
"//base",
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
"//url",
]
}
test("paint_preview_browser_unit_tests") {
deps = [
":unit_tests",
"//base",
"//base/test:test_support",
"//components/test:run_all_unittests",
]
}
}
// Copyright 2019 The Chromium 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 "components/paint_preview/browser/file_manager.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/hash/hash.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
namespace paint_preview {
namespace {
constexpr char kPaintPreviewDirname[] = "paint_preview";
std::string HashToHex(const GURL& url) {
uint32_t hash = base::PersistentHash(url.spec());
return base::HexEncode(&hash, sizeof(uint32_t));
}
} // namespace
FileManager::FileManager(const base::FilePath& root_directory)
: root_directory_(root_directory.AppendASCII(kPaintPreviewDirname)) {}
FileManager::~FileManager() = default;
size_t FileManager::GetSizeOfArtifactsFor(const GURL& url) {
return base::ComputeDirectorySize(
root_directory_.AppendASCII(HashToHex(url)));
}
bool FileManager::GetCreatedTime(const GURL& url, base::Time* created_time) {
base::File::Info info;
if (!base::GetFileInfo(root_directory_.AppendASCII(HashToHex(url)), &info))
return false;
*created_time = info.creation_time;
return true;
}
bool FileManager::GetLastAccessedTime(const GURL& url,
base::Time* last_accessed_time) {
return LastAccessedTimeInternal(root_directory_.AppendASCII(HashToHex(url)),
last_accessed_time);
}
bool FileManager::CreateOrGetDirectoryFor(const GURL& url,
base::FilePath* directory) {
base::FilePath path = root_directory_.AppendASCII(HashToHex(url));
base::File::Error error = base::File::FILE_OK;
if (base::CreateDirectoryAndGetError(path, &error)) {
*directory = path;
return true;
}
DLOG(ERROR) << "Error failed to create directory: " << path
<< " with error code " << error;
return false;
}
void FileManager::DeleteArtifactsFor(const std::vector<GURL>& urls) {
for (const auto& url : urls)
base::DeleteFile(root_directory_.AppendASCII(HashToHex(url)), true);
}
void FileManager::DeleteAll() {
base::DeleteFile(root_directory_, true);
}
void FileManager::DeleteAllOlderThan(base::Time deletion_time) {
std::vector<base::FilePath> dirs_to_delete;
base::FileEnumerator enumerator(root_directory_, false,
base::FileEnumerator::DIRECTORIES);
base::Time last_accessed_time;
for (base::FilePath dir = enumerator.Next(); !dir.empty();
dir = enumerator.Next()) {
if (!LastAccessedTimeInternal(dir, &last_accessed_time))
continue;
if (last_accessed_time < deletion_time)
dirs_to_delete.push_back(dir);
}
for (const auto& dir : dirs_to_delete)
base::DeleteFile(dir, true);
}
bool FileManager::LastAccessedTimeInternal(const base::FilePath& path,
base::Time* last_accessed_time) {
base::File::Info info;
if (!base::GetFileInfo(path, &info))
return false;
*last_accessed_time = info.last_accessed;
return true;
}
} // namespace paint_preview
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PAINT_PREVIEW_BROWSER_FILE_MANAGER_H_
#define COMPONENTS_PAINT_PREVIEW_BROWSER_FILE_MANAGER_H_
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "url/gurl.h"
namespace paint_preview {
// Manages paint preview files associated with a root directory (typically a
// user profile).
class FileManager {
public:
// Create a file manager for |root_directory|/paint_previews
explicit FileManager(const base::FilePath& root_directory);
~FileManager();
// Get statistics about the time of creation and size of artifacts.
size_t GetSizeOfArtifactsFor(const GURL& url);
bool GetCreatedTime(const GURL& url, base::Time* created_time);
bool GetLastAccessedTime(const GURL& url, base::Time* last_accessed_time);
// Creates or gets a subdirectory under |root_directory|/paint_previews/
// for |url| and assigns it to |directory|. Returns true and modifies
// |directory| on success.
bool CreateOrGetDirectoryFor(const GURL& url, base::FilePath* directory);
// Deletes artifacts associated with |urls|.
void DeleteArtifactsFor(const std::vector<GURL>& urls);
// Deletes all stored paint previews stored in the |profile_directory_|.
void DeleteAll();
// Deletes all captures with access times older than |deletion_time|. Slow and
// blocking as it relies on base::FileEnumerator.
void DeleteAllOlderThan(base::Time deletion_time);
private:
bool LastAccessedTimeInternal(const base::FilePath& path,
base::Time* last_accessed_time);
base::FilePath root_directory_;
DISALLOW_COPY_AND_ASSIGN(FileManager);
};
} // namespace paint_preview
#endif // COMPONENTS_PAINT_PREVIEW_BROWSER_FILE_MANAGER_H_
// Copyright 2019 The Chromium 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 "components/paint_preview/browser/file_manager.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace paint_preview {
TEST(FileManagerTest, TestStats) {
base::Time now = base::Time::Now();
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
FileManager manager(temp_dir.GetPath());
GURL url("https://www.chromium.org");
base::FilePath directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(url, &directory));
EXPECT_FALSE(directory.empty());
base::Time created_time;
EXPECT_TRUE(manager.GetCreatedTime(url, &created_time));
base::TouchFile(directory, now - base::TimeDelta::FromSeconds(1),
now - base::TimeDelta::FromSeconds(1));
base::Time accessed_time;
EXPECT_TRUE(manager.GetLastAccessedTime(url, &accessed_time));
base::FilePath proto_path = directory.AppendASCII("paint_preview.pb");
base::File file(proto_path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
const size_t kSize = 50;
std::string zeros(kSize, '0');
file.Write(0, zeros.data(), zeros.size());
file.Close();
base::TouchFile(directory, now + base::TimeDelta::FromSeconds(1),
now + base::TimeDelta::FromSeconds(1));
base::Time later_accessed_time;
EXPECT_TRUE(manager.GetLastAccessedTime(url, &later_accessed_time));
EXPECT_GT(later_accessed_time, accessed_time);
EXPECT_GE(manager.GetSizeOfArtifactsFor(url), kSize);
}
TEST(FileManagerTest, TestCreateOrGetDirectory) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
FileManager manager(temp_dir.GetPath());
GURL url("https://www.chromium.org");
base::FilePath new_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(url, &new_directory));
EXPECT_FALSE(new_directory.empty());
EXPECT_TRUE(base::PathExists(new_directory));
base::FilePath old_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(url, &old_directory));
EXPECT_FALSE(old_directory.empty());
EXPECT_EQ(old_directory, new_directory);
EXPECT_TRUE(base::PathExists(old_directory));
}
TEST(FileManagerTest, TestDeleteArtifactsFor) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
FileManager manager(temp_dir.GetPath());
GURL cr_url("https://www.chromium.org");
base::FilePath cr_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(cr_url, &cr_directory));
EXPECT_FALSE(cr_directory.empty());
EXPECT_TRUE(base::PathExists(cr_directory));
GURL w3_url("https://www.w3.org");
base::FilePath w3_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(w3_url, &w3_directory));
EXPECT_FALSE(w3_directory.empty());
EXPECT_TRUE(base::PathExists(w3_directory));
manager.DeleteArtifactsFor(std::vector<GURL>({cr_url}));
EXPECT_FALSE(base::PathExists(cr_directory));
EXPECT_TRUE(base::PathExists(w3_directory));
base::FilePath new_cr_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(cr_url, &new_cr_directory));
EXPECT_FALSE(new_cr_directory.empty());
EXPECT_TRUE(base::PathExists(new_cr_directory));
EXPECT_EQ(cr_directory, new_cr_directory);
manager.DeleteArtifactsFor(std::vector<GURL>({cr_url, w3_url}));
EXPECT_FALSE(base::PathExists(new_cr_directory));
EXPECT_FALSE(base::PathExists(w3_directory));
}
TEST(FileManagerTest, TestDeleteAll) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
FileManager manager(temp_dir.GetPath());
GURL cr_url("https://www.chromium.org");
base::FilePath cr_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(cr_url, &cr_directory));
EXPECT_FALSE(cr_directory.empty());
EXPECT_TRUE(base::PathExists(cr_directory));
GURL w3_url("https://www.w3.org");
base::FilePath w3_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(w3_url, &w3_directory));
EXPECT_FALSE(w3_directory.empty());
EXPECT_TRUE(base::PathExists(w3_directory));
manager.DeleteAll();
EXPECT_FALSE(base::PathExists(cr_directory));
EXPECT_FALSE(base::PathExists(w3_directory));
}
TEST(FileManagerTest, TestDeleteAllOlderThan) {
base::Time now = base::Time::Now();
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
FileManager manager(temp_dir.GetPath());
GURL cr_url("https://www.chromium.org");
base::FilePath cr_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(cr_url, &cr_directory));
EXPECT_FALSE(cr_directory.empty());
EXPECT_TRUE(base::PathExists(cr_directory));
base::TouchFile(cr_directory, now - base::TimeDelta::FromSeconds(1),
now - base::TimeDelta::FromSeconds(1));
GURL w3_url("https://www.w3.org");
base::FilePath w3_directory;
EXPECT_TRUE(manager.CreateOrGetDirectoryFor(w3_url, &w3_directory));
EXPECT_FALSE(w3_directory.empty());
EXPECT_TRUE(base::PathExists(w3_directory));
base::TouchFile(w3_directory, now + base::TimeDelta::FromSeconds(1),
now + base::TimeDelta::FromSeconds(1));
manager.DeleteAllOlderThan(now);
EXPECT_FALSE(base::PathExists(cr_directory));
EXPECT_TRUE(base::PathExists(w3_directory));
}
} // namespace paint_preview
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment