1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
// Copyright 2024 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/ash/file_system_provider/cloud_file_system.h"
#include "base/base64.h"
#include "base/files/file_util.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "chrome/browser/ash/file_manager/file_manager_test_util.h"
#include "chrome/browser/ash/file_system_provider/fake_extension_provider.h"
#include "chrome/browser/ash/file_system_provider/fake_provided_file_system.h"
#include "chrome/browser/ash/file_system_provider/service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chromeos/constants/chromeos_features.h"
#include "content/public/test/browser_test.h"
namespace ash::file_system_provider {
namespace {
const char kFileSystemId[] = "cloud-fs-id";
const char kDisplayName[] = "Cloud FS";
class MockCacheManagerObserver : public CacheManager::Observer {
public:
MOCK_METHOD(void,
OnProviderInitializationComplete,
(base::FilePath base64_encoded_provider_folder_name,
base::File::Error result),
(override));
MOCK_METHOD(void,
OnProviderUninitialized,
(base::FilePath base64_encoded_provider_folder_name,
base::File::Error result),
(override));
};
// Fake extension provider to create a `a `CloudFileSystem` wrapping by a
// `FakeProvidedFileSystem`. This also observes the `CacheManager`, if it is
// provided.
class FakeExtensionProviderForCloudFileSystem : public FakeExtensionProvider {
public:
static std::unique_ptr<ProviderInterface> Create(
const extensions::ExtensionId& extension_id,
base::OnceCallback<void(CacheManager* cache_manager)> on_cache_manager) {
Capabilities default_capabilities(false, false, false,
extensions::SOURCE_NETWORK);
return std::make_unique<FakeExtensionProviderForCloudFileSystem>(
extension_id, default_capabilities, std::move(on_cache_manager));
}
FakeExtensionProviderForCloudFileSystem(
const extensions::ExtensionId& extension_id,
const Capabilities& capabilities,
base::OnceCallback<void(CacheManager* cache_manager)> on_cache_manager)
: FakeExtensionProvider(extension_id, capabilities),
on_cache_manager_(std::move(on_cache_manager)) {}
// This will be called by the `Service::MountFileSystem()` and will lead to a
// `CloudFileSystem` being mounted. Return a `CloudFileSystem` wrapping by a
// `FakeProvidedFileSystem`. This will include a content cache if the
// `FileSystemProviderContentCache` flag is set and the provider is ODFS
// because the `cache_manager` would have been created. This logic mirrors the
// real `ExtensionProvider::CreateProvidedFileSystem()`. Also call the
// `on_cache_manager_` callback with the provided `cache_manager`.
std::unique_ptr<ProvidedFileSystemInterface> CreateProvidedFileSystem(
Profile* profile,
const ProvidedFileSystemInfo& file_system_info,
CacheManager* cache_manager) override {
EXPECT_TRUE(
chromeos::features::IsFileSystemProviderCloudFileSystemEnabled());
std::move(on_cache_manager_).Run(cache_manager);
if (file_system_info.cache_type() != CacheType::NONE) {
// CloudFileSystem with cache.
return std::make_unique<CloudFileSystem>(
std::make_unique<FakeProvidedFileSystem>(file_system_info),
cache_manager);
}
// CloudFileSystem without cache.
return std::make_unique<CloudFileSystem>(
std::make_unique<FakeProvidedFileSystem>(file_system_info));
}
private:
base::OnceCallback<void(CacheManager* cache_manager)> on_cache_manager_;
};
} // namespace
class CloudFileSystemBrowserTest : public InProcessBrowserTest {
public:
CloudFileSystemBrowserTest() = default;
Profile* profile() { return browser()->profile(); }
protected:
base::test::ScopedFeatureList feature_list_;
};
class CloudFileSystemBrowserTestWithContentCache
: public CloudFileSystemBrowserTest {
protected:
CloudFileSystemBrowserTestWithContentCache() {
feature_list_.InitWithFeatures(
{chromeos::features::kFileSystemProviderCloudFileSystem,
chromeos::features::kFileSystemProviderContentCache},
{});
}
const base::FilePath GetProviderMountPath(
base::FilePath base64_encoded_provider_folder_name) {
return profile()
->GetPath()
.Append(kFspContentCacheDirName)
.Append(base64_encoded_provider_folder_name);
}
};
// Tests that a CacheManager is created when mounting a CloudFileSystem when
// `kFileSystemProviderCloudFileSystem` and `kFileSystemProviderContentCache`
// are enabled. Tests that a ContentCache is initialized on the CacheManager
// upon mount and is uninitialized upon unmount via the user.
IN_PROC_BROWSER_TEST_F(
CloudFileSystemBrowserTestWithContentCache,
ContentCacheInitializedOnMountAndUninitializedOnUnmountByUser) {
// Catch the cache_manager pointer before it's passed to the CloudFileSystem
// constructor.
MockCacheManagerObserver observer;
base::OnceCallback<void(CacheManager * cache_manager)> on_cache_manager =
base::BindLambdaForTesting([&](CacheManager* cache_manager) {
// Expect the cache manager to have been created.
ASSERT_TRUE(cache_manager);
cache_manager->AddObserver(&observer);
});
// Mount a CloudFileSystem.
// Specifically mount ODFS as Service::MountFileSystem() will only use a
// CacheManager if kFileSystemProviderCloudFileSystem and
// kFileSystemProviderContentCache are set and the extension is ODFS.
MountOptions mount_options(kFileSystemId, kDisplayName);
ProvidedFileSystemInterface* cloud_file_system =
file_manager::test::MountProvidedFileSystem(
profile(), extension_misc::kODFSExtensionId, mount_options,
FakeExtensionProviderForCloudFileSystem::Create(
extension_misc::kODFSExtensionId, std::move(on_cache_manager)));
// Wait for the provider to be initialized on the CacheManager.
base::RunLoop run_loop1;
const base::FilePath base64_encoded_provider_folder_name(base::Base64Encode(
cloud_file_system->GetFileSystemInfo().mount_path().BaseName().value()));
EXPECT_CALL(observer,
OnProviderInitializationComplete(
base64_encoded_provider_folder_name, base::File::FILE_OK))
.WillOnce(base::test::RunClosure(run_loop1.QuitClosure()));
run_loop1.Run();
// Check provider cache folder exists.
{
base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_TRUE(base::PathExists(
GetProviderMountPath(base64_encoded_provider_folder_name)));
}
// Unmount.
Service* service = Service::Get(profile());
service->UnmountFileSystem(
cloud_file_system->GetFileSystemInfo().provider_id(),
cloud_file_system->GetFileSystemInfo().file_system_id(),
Service::UnmountReason::UNMOUNT_REASON_USER);
// Wait for the provider to be uninitialized on the CacheManager.
base::RunLoop run_loop2;
EXPECT_CALL(observer,
OnProviderUninitialized(base64_encoded_provider_folder_name,
base::File::FILE_OK))
.WillOnce(base::test::RunClosure(run_loop2.QuitClosure()));
run_loop2.Run();
// Check provider cache folder deleted.
{
base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_FALSE(base::PathExists(
GetProviderMountPath(base64_encoded_provider_folder_name)));
}
}
// Tests that the content cache remains if unmount is performed by the system.
IN_PROC_BROWSER_TEST_F(CloudFileSystemBrowserTestWithContentCache,
ContentCacheNotUninitializedOnUnmountByShutdown) {
// Catch the cache_manager pointer before it's passed to the CloudFileSystem
// constructor.
MockCacheManagerObserver observer;
base::OnceCallback<void(CacheManager * cache_manager)> on_cache_manager =
base::BindLambdaForTesting([&](CacheManager* cache_manager) {
// Expect the cache manager to have been created.
ASSERT_TRUE(cache_manager);
cache_manager->AddObserver(&observer);
});
// Mount a CloudFileSystem.
// Specifically mount ODFS as Service::MountFileSystem() will only use a
// CacheManager if kFileSystemProviderCloudFileSystem and
// kFileSystemProviderContentCache are set and the extension is ODFS.
MountOptions mount_options(kFileSystemId, kDisplayName);
ProvidedFileSystemInterface* cloud_file_system =
file_manager::test::MountProvidedFileSystem(
profile(), extension_misc::kODFSExtensionId, mount_options,
FakeExtensionProviderForCloudFileSystem::Create(
extension_misc::kODFSExtensionId, std::move(on_cache_manager)));
// Wait for the provider to be initialized on the CacheManager.
base::RunLoop run_loop;
const base::FilePath base64_encoded_provider_folder_name(base::Base64Encode(
cloud_file_system->GetFileSystemInfo().mount_path().BaseName().value()));
EXPECT_CALL(observer,
OnProviderInitializationComplete(
base64_encoded_provider_folder_name, base::File::FILE_OK))
.WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
run_loop.Run();
// Expect that the Provider won't be uninitialized.
EXPECT_CALL(observer, OnProviderUninitialized(testing::_, testing::_))
.Times(0);
// Unmount.
Service* service = Service::Get(profile());
service->UnmountFileSystem(
cloud_file_system->GetFileSystemInfo().provider_id(),
cloud_file_system->GetFileSystemInfo().file_system_id(),
Service::UnmountReason::UNMOUNT_REASON_SHUTDOWN);
}
class CloudFileSystemBrowserTestWithoutContentCache
: public CloudFileSystemBrowserTest {
protected:
CloudFileSystemBrowserTestWithoutContentCache() {
feature_list_.InitWithFeatures(
{chromeos::features::kFileSystemProviderCloudFileSystem},
{chromeos::features::kFileSystemProviderContentCache});
}
};
// Tests that a CacheManager is not created when mounting a CloudFileSystem when
// `kFileSystemProviderCloudFileSystem` is enabled but
// `kFileSystemProviderContentCache` isn't.
IN_PROC_BROWSER_TEST_F(CloudFileSystemBrowserTestWithoutContentCache,
CacheManagerNotCreated) {
// Mount a CloudFileSystem.
MountOptions mount_options(kFileSystemId, kDisplayName);
base::OnceCallback<void(CacheManager * cache_manager)> on_cache_manager =
base::BindLambdaForTesting([](CacheManager* cache_manager) {
// Expect the cache manager to not have been created.
ASSERT_FALSE(cache_manager);
});
// Specifically mount ODFS as Service::MountFileSystem() will only use a
// CacheManager if kFileSystemProviderCloudFileSystem and
// kFileSystemProviderContentCache are set and the extension is ODFS.
file_manager::test::MountProvidedFileSystem(
profile(), extension_misc::kODFSExtensionId, mount_options,
FakeExtensionProviderForCloudFileSystem::Create(
extension_misc::kODFSExtensionId, std::move(on_cache_manager)));
}
} // namespace ash::file_system_provider
|