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
5 #include "base/run_loop.h"
6 #include "base/test/bind.h"
7 #include "base/test/scoped_feature_list.h"
8 #include "base/threading/sequenced_task_runner_handle.h"
9 #include "build/build_config.h"
10 #include "components/services/storage/public/mojom/storage_service.mojom.h"
11 #include "components/services/storage/public/mojom/test_api.test-mojom.h"
12 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
13 #include "content/browser/storage_partition_impl.h"
14 #include "content/public/browser/browser_context.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/common/content_features.h"
17 #include "content/public/test/browser_test.h"
18 #include "content/public/test/browser_test_utils.h"
19 #include "content/public/test/content_browser_test.h"
20 #include "content/public/test/content_browser_test_utils.h"
21 #include "content/shell/browser/shell.h"
22 #include "mojo/public/cpp/bindings/sync_call_restrictions.h"
23
24 namespace content {
25 namespace {
26
27 class StorageServiceSandboxBrowserTest : public ContentBrowserTest {
28 public:
StorageServiceSandboxBrowserTest()29 StorageServiceSandboxBrowserTest() {
30 // These tests only make sense when the service is running out-of-process
31 // with sandboxing enabled.
32 feature_list_.InitWithFeatures({features::kStorageServiceOutOfProcess}, {});
33 }
34
dom_storage()35 DOMStorageContextWrapper* dom_storage() {
36 auto* partition = static_cast<StoragePartitionImpl*>(
37 BrowserContext::GetDefaultStoragePartition(
38 shell()->web_contents()->GetBrowserContext()));
39 return partition->GetDOMStorageContext();
40 }
41
WaitForAnyLocalStorageDataAsync(base::OnceClosure callback)42 void WaitForAnyLocalStorageDataAsync(base::OnceClosure callback) {
43 dom_storage()->GetLocalStorageControl()->GetUsage(base::BindOnce(
44 [](StorageServiceSandboxBrowserTest* test, base::OnceClosure callback,
45 std::vector<storage::mojom::LocalStorageUsageInfoPtr> usage) {
46 if (!usage.empty()) {
47 std::move(callback).Run();
48 return;
49 }
50
51 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
52 FROM_HERE,
53 base::BindOnce(&StorageServiceSandboxBrowserTest::
54 WaitForAnyLocalStorageDataAsync,
55 base::Unretained(test), std::move(callback)),
56 base::TimeDelta::FromMilliseconds(50));
57 },
58 this, std::move(callback)));
59 }
60
WaitForAnyLocalStorageData()61 void WaitForAnyLocalStorageData() {
62 base::RunLoop loop;
63 WaitForAnyLocalStorageDataAsync(loop.QuitClosure());
64 loop.Run();
65 }
66
FlushLocalStorage()67 void FlushLocalStorage() {
68 base::RunLoop loop;
69 dom_storage()->GetLocalStorageControl()->Flush(loop.QuitClosure());
70 loop.Run();
71 }
72
GetTestApi()73 mojo::Remote<storage::mojom::TestApi>& GetTestApi() {
74 if (!test_api_) {
75 StoragePartitionImpl::GetStorageServiceForTesting()->BindTestApi(
76 test_api_.BindNewPipeAndPassReceiver().PassPipe());
77 }
78 return test_api_;
79 }
80
81 private:
82 base::test::ScopedFeatureList feature_list_;
83 mojo::Remote<storage::mojom::TestApi> test_api_;
84 };
85
IN_PROC_BROWSER_TEST_F(StorageServiceSandboxBrowserTest,BasicLaunch)86 IN_PROC_BROWSER_TEST_F(StorageServiceSandboxBrowserTest, BasicLaunch) {
87 // Basic smoke test to ensure that we can launch the Storage Service in a
88 // sandboxed and it won't crash immediately.
89 GetTestApi().FlushForTesting();
90 EXPECT_TRUE(GetTestApi().is_connected());
91 }
92
IN_PROC_BROWSER_TEST_F(StorageServiceSandboxBrowserTest,PRE_DomStorage)93 IN_PROC_BROWSER_TEST_F(StorageServiceSandboxBrowserTest, PRE_DomStorage) {
94 EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "empty.html")));
95 ignore_result(
96 EvalJs(shell()->web_contents(), R"(window.localStorage.yeet = 42)"));
97 WaitForAnyLocalStorageData();
98 FlushLocalStorage();
99 }
100
IN_PROC_BROWSER_TEST_F(StorageServiceSandboxBrowserTest,DomStorage)101 IN_PROC_BROWSER_TEST_F(StorageServiceSandboxBrowserTest, DomStorage) {
102 // Tests that Local Storage data persists from the PRE test setup above,
103 // providing basic assurance that the sandboxed process is able to manipulate
104 // filesystem contents as needed.
105 EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "empty.html")));
106 EXPECT_EQ("42",
107 EvalJs(shell()->web_contents(), R"(window.localStorage.yeet)"));
108 }
109
IN_PROC_BROWSER_TEST_F(StorageServiceSandboxBrowserTest,CompactDatabase)110 IN_PROC_BROWSER_TEST_F(StorageServiceSandboxBrowserTest, CompactDatabase) {
111 // Tests that the sandboxed service can execute a LevelDB database compaction
112 // operation without crashing. If the service crashes, the sync call below
113 // will return false.
114 mojo::ScopedAllowSyncCallForTesting allow_sync_calls;
115 EXPECT_TRUE(
116 GetTestApi()->ForceLeveldbDatabaseCompaction("CompactDatabaseTestDb"));
117 }
118
119 } // namespace
120 } // namespace content
121