blob: a04c22c66d01d21fda99708d62f0a163d47a0387 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/profiles/profile.h"
#include <stddef.h>
#include <memory>
#include "base/bind.h"
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/ui/android/tab_model/tab_model.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/test/base/android/android_browser_test.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
class ProfileDeleteMediaBrowserTest : public AndroidBrowserTest {
protected:
void SetUp() override {
// This needs to happen before AndroidBrowserTest::SetUp(), since that
// invokes deletion. Luckily on Android chrome::GetUserCacheDirectory()
// doesn't actually look at its input. (This would be cleaner as a PRE_
// test, but that doesn't appear to be supported here).
chrome::GetUserCacheDirectory(base::FilePath(), &cache_base_);
base::FilePath media_cache_path =
cache_base_.Append(chrome::kMediaCacheDirname);
base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_TRUE(base::CreateDirectory(media_cache_path));
std::string data = "foo";
base::WriteFile(media_cache_path.AppendASCII("foo"), data);
AndroidBrowserTest::SetUp();
}
base::FilePath cache_base_;
};
namespace {
// Watches for the destruction of the specified path (Which, in the tests that
// use it, is typically a directory), and expects the parent directory not to be
// deleted.
//
// The public methods are called on the UI thread, the private ones called on a
// separate SequencedTaskRunner.
class FileDestructionWatcher {
public:
explicit FileDestructionWatcher(const base::FilePath& watched_file_path)
: watched_file_path_(watched_file_path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}
FileDestructionWatcher(const FileDestructionWatcher&) = delete;
FileDestructionWatcher& operator=(const FileDestructionWatcher&) = delete;
void WaitForDestruction() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(!watcher_);
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})
->PostTask(FROM_HERE,
base::BindOnce(&FileDestructionWatcher::StartWatchingPath,
base::Unretained(this)));
run_loop_.Run();
// The watcher should be destroyed before quitting the run loop, once the
// file has been destroyed.
DCHECK(!watcher_);
// Double check that the file was destroyed, and that the parent directory
// was not.
base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_FALSE(base::PathExists(watched_file_path_));
EXPECT_TRUE(base::PathExists(watched_file_path_.DirName()));
}
private:
void StartWatchingPath() {
DCHECK(!watcher_);
watcher_ = std::make_unique<base::FilePathWatcher>();
// Start watching before checking if the file exists, as the file could be
// destroyed between the existence check and when we start watching, if the
// order were reversed.
EXPECT_TRUE(watcher_->Watch(
watched_file_path_, base::FilePathWatcher::Type::kNonRecursive,
base::BindRepeating(&FileDestructionWatcher::OnPathChanged,
base::Unretained(this))));
CheckIfPathExists();
}
void OnPathChanged(const base::FilePath& path, bool error) {
EXPECT_EQ(watched_file_path_, path);
EXPECT_FALSE(error);
CheckIfPathExists();
}
// Checks if the path exists, and if so, destroys the watcher and quits
// |run_loop_|.
void CheckIfPathExists() {
if (!base::PathExists(watched_file_path_)) {
watcher_.reset();
run_loop_.Quit();
return;
}
}
base::RunLoop run_loop_;
const base::FilePath watched_file_path_;
// Created and destroyed off of the UI thread, on the sequence used to watch
// for changes.
std::unique_ptr<base::FilePathWatcher> watcher_;
};
} // namespace
IN_PROC_BROWSER_TEST_F(ProfileDeleteMediaBrowserTest, DeleteMediaCache) {
// Make sure the legacy media cache directory (created in SetUp) gets deleted
// properly.
base::FilePath cache_base;
chrome::GetUserCacheDirectory(
TabModelList::models()[0]->GetProfile()->GetPath(), &cache_base);
// |cache_base_| computation in SetUp() makes assumptions on implementation
// details to be able to run that early, so verify its result is sane.
EXPECT_EQ(cache_base, cache_base_);
base::FilePath media_cache_path =
cache_base.Append(chrome::kMediaCacheDirname);
base::ScopedAllowBlockingForTesting allow_blocking;
FileDestructionWatcher destruction_watcher(media_cache_path);
destruction_watcher.WaitForDestruction();
}