sandbox_file_stream_writer_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "storage/browser/file_system/sandbox_file_stream_writer.h"
  5. #include "base/test/test_future.h"
  6. #include "storage/browser/file_system/file_stream_writer_test.h"
  7. #include <stdint.h>
  8. #include <memory>
  9. #include <string>
  10. #include "base/bind.h"
  11. #include "base/callback_helpers.h"
  12. #include "base/files/file_util.h"
  13. #include "base/files/scoped_temp_dir.h"
  14. #include "base/time/time.h"
  15. #include "components/services/storage/public/cpp/buckets/bucket_info.h"
  16. #include "components/services/storage/public/cpp/buckets/constants.h"
  17. #include "components/services/storage/public/cpp/quota_error_or.h"
  18. #include "net/base/io_buffer.h"
  19. #include "net/base/net_errors.h"
  20. #include "storage/browser/file_system/file_stream_reader.h"
  21. #include "storage/browser/file_system/file_stream_test_utils.h"
  22. #include "storage/browser/file_system/file_stream_writer.h"
  23. #include "storage/browser/file_system/file_system_context.h"
  24. #include "storage/browser/quota/quota_manager_proxy.h"
  25. #include "storage/browser/test/async_file_test_helper.h"
  26. #include "storage/browser/test/mock_quota_manager_proxy.h"
  27. #include "storage/browser/test/mock_special_storage_policy.h"
  28. #include "storage/browser/test/quota_manager_proxy_sync.h"
  29. #include "storage/browser/test/test_file_system_context.h"
  30. #include "storage/common/file_system/file_system_types.h"
  31. #include "third_party/blink/public/common/storage_key/storage_key.h"
  32. namespace storage {
  33. namespace {
  34. const char kURLOrigin[] = "http://remote/";
  35. } // namespace
  36. class SandboxFileStreamWriterTest : public FileStreamWriterTest {
  37. public:
  38. SandboxFileStreamWriterTest()
  39. : special_storage_policy_(
  40. base::MakeRefCounted<MockSpecialStoragePolicy>()) {}
  41. ~SandboxFileStreamWriterTest() override = default;
  42. void SetUp() override {
  43. ASSERT_TRUE(dir_.CreateUniqueTempDir());
  44. quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>(
  45. is_incognito(), dir_.GetPath(), base::ThreadTaskRunnerHandle::Get(),
  46. special_storage_policy_);
  47. quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>(
  48. quota_manager_.get(), base::ThreadTaskRunnerHandle::Get());
  49. file_system_context_ =
  50. CreateFileSystemContext(quota_manager_proxy_.get(), dir_);
  51. file_system_context_->OpenFileSystem(
  52. blink::StorageKey::CreateFromStringForTesting(kURLOrigin),
  53. /*bucket=*/absl::nullopt, kFileSystemTypeTemporary,
  54. OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
  55. base::BindOnce([](const FileSystemURL& root_url,
  56. const std::string& name, base::File::Error result) {
  57. ASSERT_EQ(base::File::FILE_OK, result);
  58. }));
  59. SetQuota(1024 * 1024 * 100);
  60. base::RunLoop().RunUntilIdle();
  61. }
  62. void TearDown() override {
  63. quota_manager_proxy_ = nullptr;
  64. quota_manager_ = nullptr;
  65. base::RunLoop().RunUntilIdle();
  66. }
  67. protected:
  68. scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
  69. scoped_refptr<FileSystemContext> file_system_context_;
  70. scoped_refptr<MockQuotaManager> quota_manager_;
  71. scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
  72. struct quota_usage_and_info {
  73. blink::mojom::QuotaStatusCode status;
  74. int64_t usage;
  75. int64_t quota;
  76. };
  77. virtual scoped_refptr<FileSystemContext> CreateFileSystemContext(
  78. QuotaManagerProxy* quota_manager_proxy,
  79. const base::ScopedTempDir& dir) {
  80. return CreateFileSystemContextForTesting(quota_manager_proxy,
  81. dir.GetPath());
  82. }
  83. virtual bool is_incognito() { return false; }
  84. FileSystemURL GetFileSystemURL(const std::string& file_name) {
  85. return file_system_context_->CreateCrackedFileSystemURL(
  86. blink::StorageKey::CreateFromStringForTesting(kURLOrigin),
  87. kFileSystemTypeTemporary, base::FilePath().AppendASCII(file_name));
  88. }
  89. bool CreateFileWithContent(const std::string& name,
  90. const std::string& data) override {
  91. return AsyncFileTestHelper::CreateFileWithData(
  92. file_system_context_.get(), GetFileSystemURL(name), data.data(),
  93. data.size()) == base::File::FILE_OK;
  94. }
  95. std::unique_ptr<FileStreamWriter> CreateWriter(const std::string& name,
  96. int64_t offset) override {
  97. auto writer = std::make_unique<SandboxFileStreamWriter>(
  98. file_system_context_.get(), GetFileSystemURL(name), offset,
  99. *file_system_context_->GetUpdateObservers(kFileSystemTypeTemporary));
  100. return writer;
  101. }
  102. bool FilePathExists(const std::string& name) override {
  103. return AsyncFileTestHelper::FileExists(file_system_context_.get(),
  104. GetFileSystemURL(name),
  105. AsyncFileTestHelper::kDontCheckSize);
  106. }
  107. std::string GetFileContent(const std::string& name) override {
  108. base::File::Info info;
  109. const FileSystemURL url = GetFileSystemURL(name);
  110. EXPECT_EQ(base::File::FILE_OK, AsyncFileTestHelper::GetMetadata(
  111. file_system_context_.get(), url, &info));
  112. std::unique_ptr<FileStreamReader> reader(
  113. file_system_context_.get()->CreateFileStreamReader(url, 0, info.size,
  114. base::Time()));
  115. int result = 0;
  116. std::string content;
  117. ReadFromReader(reader.get(), &content, info.size, &result);
  118. EXPECT_EQ(net::OK, result);
  119. EXPECT_EQ(info.size, long(content.length()));
  120. return content;
  121. }
  122. std::unique_ptr<SandboxFileStreamWriter> CreateSandboxWriter(
  123. const std::string& name,
  124. int64_t offset) {
  125. auto writer = std::make_unique<SandboxFileStreamWriter>(
  126. file_system_context_.get(), GetFileSystemURL(name), offset,
  127. *file_system_context_->GetUpdateObservers(kFileSystemTypeTemporary));
  128. return writer;
  129. }
  130. quota_usage_and_info GetUsageAndQuotaSync() {
  131. base::test::TestFuture<blink::mojom::QuotaStatusCode, int64_t, int64_t>
  132. future;
  133. quota_manager_->GetUsageAndQuota(
  134. blink::StorageKey::CreateFromStringForTesting(kURLOrigin),
  135. blink::mojom::StorageType::kTemporary, future.GetCallback());
  136. quota_usage_and_info info;
  137. info.status = future.Get<0>();
  138. info.usage = future.Get<1>();
  139. info.quota = future.Get<2>();
  140. return info;
  141. }
  142. void SetQuota(int64_t quota) {
  143. quota_manager_->SetQuota(
  144. blink::StorageKey::CreateFromStringForTesting(kURLOrigin),
  145. blink::mojom::StorageType::kTemporary, quota);
  146. }
  147. int64_t GetFreeQuota() {
  148. auto info = GetUsageAndQuotaSync();
  149. return info.quota - info.usage;
  150. }
  151. void SetFreeQuota(int64_t free_quota) {
  152. auto info = GetUsageAndQuotaSync();
  153. SetQuota(info.usage + free_quota);
  154. }
  155. void Test_Quota_DefaultBucketCreated() {
  156. // Call method on context to ensure that OpenFileSystem task has completed.
  157. EXPECT_TRUE(CreateFileWithContent("file_a", "foo"));
  158. QuotaManagerProxySync quota_manager_proxy_sync(quota_manager_proxy_.get());
  159. // Check default bucket exist.
  160. QuotaErrorOr<BucketInfo> result = quota_manager_proxy_sync.GetBucket(
  161. blink::StorageKey::CreateFromStringForTesting(kURLOrigin),
  162. kDefaultBucketName, blink::mojom::StorageType::kTemporary);
  163. EXPECT_TRUE(result.ok());
  164. EXPECT_EQ(result->name, kDefaultBucketName);
  165. EXPECT_EQ(result->storage_key,
  166. blink::StorageKey::CreateFromStringForTesting(kURLOrigin));
  167. EXPECT_GT(result->id.value(), 0);
  168. }
  169. void Test_Quota_OK() {
  170. std::string name = "file_a";
  171. EXPECT_TRUE(CreateFileWithContent(name, "foo"));
  172. SetFreeQuota(7);
  173. std::unique_ptr<SandboxFileStreamWriter> writer(
  174. CreateSandboxWriter(name, 3));
  175. EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
  176. writer.reset();
  177. base::RunLoop().RunUntilIdle();
  178. EXPECT_TRUE(FilePathExists(name));
  179. EXPECT_EQ(std::string("fooxxx", 6), GetFileContent(name));
  180. EXPECT_EQ(GetFreeQuota(), 4);
  181. }
  182. void Test_Quota_WritePastEnd() {
  183. std::string name = "file_a";
  184. EXPECT_TRUE(CreateFileWithContent(name, "foo"));
  185. SetFreeQuota(6);
  186. std::unique_ptr<SandboxFileStreamWriter> writer(
  187. CreateSandboxWriter(name, 6));
  188. EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
  189. writer.reset();
  190. base::RunLoop().RunUntilIdle();
  191. EXPECT_TRUE(FilePathExists(name));
  192. EXPECT_EQ(std::string("foo\0\0\0xxx", 9), GetFileContent(name));
  193. EXPECT_EQ(GetFreeQuota(), 0);
  194. }
  195. void Test_Quota_NoSpace() {
  196. std::string name = "file_a";
  197. EXPECT_TRUE(CreateFileWithContent(name, "foo"));
  198. SetFreeQuota(0);
  199. std::unique_ptr<SandboxFileStreamWriter> writer(
  200. CreateSandboxWriter(name, 3));
  201. EXPECT_EQ(net::ERR_FILE_NO_SPACE, WriteStringToWriter(writer.get(), "xxx"));
  202. writer.reset();
  203. base::RunLoop().RunUntilIdle();
  204. EXPECT_TRUE(FilePathExists(name));
  205. EXPECT_EQ(std::string("foo", 3), GetFileContent(name));
  206. EXPECT_EQ(GetFreeQuota(), 0);
  207. }
  208. void Test_Quota_NoSpace_PartialWrite() {
  209. std::string name = "file_a";
  210. EXPECT_TRUE(CreateFileWithContent(name, "foo"));
  211. SetFreeQuota(5);
  212. std::unique_ptr<SandboxFileStreamWriter> writer(
  213. CreateSandboxWriter(name, 6));
  214. EXPECT_EQ(net::ERR_FILE_NO_SPACE, WriteStringToWriter(writer.get(), "xxx"));
  215. writer.reset();
  216. base::RunLoop().RunUntilIdle();
  217. EXPECT_TRUE(FilePathExists(name));
  218. EXPECT_EQ(std::string("foo\0\0\0xx", 8), GetFileContent(name));
  219. EXPECT_EQ(GetFreeQuota(), 0);
  220. }
  221. void Test_Quota_Negative() {
  222. std::string name = "file_a";
  223. EXPECT_TRUE(CreateFileWithContent(name, "foo"));
  224. SetFreeQuota(-1);
  225. std::unique_ptr<SandboxFileStreamWriter> writer(
  226. CreateSandboxWriter(name, 3));
  227. EXPECT_EQ(net::ERR_FILE_NO_SPACE, WriteStringToWriter(writer.get(), "xxx"));
  228. writer.reset();
  229. base::RunLoop().RunUntilIdle();
  230. EXPECT_TRUE(FilePathExists(name));
  231. EXPECT_EQ(std::string("foo", 3), GetFileContent(name));
  232. EXPECT_EQ(GetFreeQuota(), -1);
  233. }
  234. void Test_Quota_WritePastEndTwice_OK() {
  235. std::string name = "file_a";
  236. EXPECT_TRUE(CreateFileWithContent(name, "foo"));
  237. SetFreeQuota(9);
  238. std::unique_ptr<SandboxFileStreamWriter> writer(
  239. CreateSandboxWriter(name, 6));
  240. EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
  241. EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "yyy"));
  242. writer.reset();
  243. base::RunLoop().RunUntilIdle();
  244. EXPECT_TRUE(FilePathExists(name));
  245. EXPECT_EQ(std::string("foo\0\0\0xxxyyy", 12), GetFileContent(name));
  246. EXPECT_EQ(GetFreeQuota(), 0);
  247. }
  248. void Test_Quota_WritePastEndTwice_NoSpace() {
  249. std::string name = "file_a";
  250. EXPECT_TRUE(CreateFileWithContent(name, "foo"));
  251. SetFreeQuota(7);
  252. std::unique_ptr<SandboxFileStreamWriter> writer(
  253. CreateSandboxWriter(name, 6));
  254. EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx"));
  255. EXPECT_EQ(net::ERR_FILE_NO_SPACE, WriteStringToWriter(writer.get(), "yyy"));
  256. writer.reset();
  257. base::RunLoop().RunUntilIdle();
  258. EXPECT_TRUE(FilePathExists(name));
  259. EXPECT_EQ(std::string("foo\0\0\0xxxy", 10), GetFileContent(name));
  260. EXPECT_EQ(GetFreeQuota(), 0);
  261. }
  262. };
  263. TEST_F(SandboxFileStreamWriterTest, Test_Quota_DefaultBucketCreated) {
  264. Test_Quota_DefaultBucketCreated();
  265. }
  266. TEST_F(SandboxFileStreamWriterTest, Quota_OK) {
  267. Test_Quota_OK();
  268. }
  269. TEST_F(SandboxFileStreamWriterTest, Quota_WritePastEnd) {
  270. Test_Quota_WritePastEnd();
  271. }
  272. TEST_F(SandboxFileStreamWriterTest, Quota_NoSpace) {
  273. Test_Quota_NoSpace();
  274. }
  275. TEST_F(SandboxFileStreamWriterTest, Quota_NoSpace_PartialWrite) {
  276. Test_Quota_NoSpace_PartialWrite();
  277. }
  278. TEST_F(SandboxFileStreamWriterTest, Quota_Negative) {
  279. Test_Quota_Negative();
  280. }
  281. TEST_F(SandboxFileStreamWriterTest, Quota_WritePastEndTwice_OK) {
  282. Test_Quota_WritePastEndTwice_OK();
  283. }
  284. TEST_F(SandboxFileStreamWriterTest, Quota_WritePastEndTwice_NoSpace) {
  285. Test_Quota_WritePastEndTwice_NoSpace();
  286. }
  287. INSTANTIATE_TYPED_TEST_SUITE_P(Sandbox,
  288. FileStreamWriterTypedTest,
  289. SandboxFileStreamWriterTest);
  290. class SandboxFileStreamWriterIncognitoTest
  291. : public SandboxFileStreamWriterTest {
  292. public:
  293. SandboxFileStreamWriterIncognitoTest() = default;
  294. protected:
  295. scoped_refptr<FileSystemContext> CreateFileSystemContext(
  296. QuotaManagerProxy* quota_manager_proxy,
  297. const base::ScopedTempDir& dir) override {
  298. return CreateIncognitoFileSystemContextForTesting(
  299. base::ThreadTaskRunnerHandle::Get(),
  300. base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy,
  301. dir.GetPath());
  302. }
  303. bool is_incognito() override { return true; }
  304. };
  305. TEST_F(SandboxFileStreamWriterIncognitoTest, Test_Quota_DefaultBucketCreated) {
  306. Test_Quota_DefaultBucketCreated();
  307. }
  308. TEST_F(SandboxFileStreamWriterIncognitoTest, Quota_OK) {
  309. Test_Quota_OK();
  310. }
  311. TEST_F(SandboxFileStreamWriterIncognitoTest, Quota_WritePastEnd) {
  312. Test_Quota_WritePastEnd();
  313. }
  314. TEST_F(SandboxFileStreamWriterIncognitoTest, Quota_NoSpace) {
  315. Test_Quota_NoSpace();
  316. }
  317. TEST_F(SandboxFileStreamWriterIncognitoTest, Quota_NoSpace_PartialWrite) {
  318. Test_Quota_NoSpace_PartialWrite();
  319. }
  320. TEST_F(SandboxFileStreamWriterIncognitoTest, Quota_Negative) {
  321. Test_Quota_Negative();
  322. }
  323. TEST_F(SandboxFileStreamWriterIncognitoTest, Quota_WritePastEndTwice_OK) {
  324. Test_Quota_WritePastEndTwice_OK();
  325. }
  326. TEST_F(SandboxFileStreamWriterIncognitoTest, Quota_WritePastEndTwice_NoSpace) {
  327. Test_Quota_WritePastEndTwice_NoSpace();
  328. }
  329. INSTANTIATE_TYPED_TEST_SUITE_P(SandboxIncognito,
  330. FileStreamWriterTypedTest,
  331. SandboxFileStreamWriterIncognitoTest);
  332. } // namespace storage